mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2025-06-08 07:03:02 -04:00
wip: WithdrawDialog migrated to Tauri IPC
This commit is contained in:
parent
47821cbe79
commit
3d16ff6d5c
118 changed files with 1779 additions and 1868 deletions
|
@ -24,5 +24,5 @@ export interface Alert {
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
body: string;
|
body: string;
|
||||||
severity: 'info' | 'warning' | 'error';
|
severity: "info" | "warning" | "error";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
export enum SwapSpawnType {
|
export enum SwapSpawnType {
|
||||||
INIT = 'init',
|
INIT = "init",
|
||||||
RESUME = 'resume',
|
RESUME = "resume",
|
||||||
CANCEL_REFUND = 'cancel-refund',
|
CANCEL_REFUND = "cancel-refund",
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CliLogSpanType = string | 'BitcoinWalletSubscription';
|
export type CliLogSpanType = string | "BitcoinWalletSubscription";
|
||||||
|
|
||||||
export interface CliLog {
|
export interface CliLog {
|
||||||
timestamp: string;
|
timestamp: string;
|
||||||
level: 'DEBUG' | 'INFO' | 'WARN' | 'ERROR' | 'TRACE';
|
level: "DEBUG" | "INFO" | "WARN" | "ERROR" | "TRACE";
|
||||||
fields: {
|
fields: {
|
||||||
message: string;
|
message: string;
|
||||||
[index: string]: unknown;
|
[index: string]: unknown;
|
||||||
|
@ -20,12 +20,12 @@ export interface CliLog {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isCliLog(log: unknown): log is CliLog {
|
export function isCliLog(log: unknown): log is CliLog {
|
||||||
if (log && typeof log === 'object') {
|
if (log && typeof log === "object") {
|
||||||
return (
|
return (
|
||||||
'timestamp' in (log as CliLog) &&
|
"timestamp" in (log as CliLog) &&
|
||||||
'level' in (log as CliLog) &&
|
"level" in (log as CliLog) &&
|
||||||
'fields' in (log as CliLog) &&
|
"fields" in (log as CliLog) &&
|
||||||
typeof (log as CliLog).fields?.message === 'string'
|
typeof (log as CliLog).fields?.message === "string"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -33,7 +33,7 @@ export function isCliLog(log: unknown): log is CliLog {
|
||||||
|
|
||||||
export interface CliLogStartedRpcServer extends CliLog {
|
export interface CliLogStartedRpcServer extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'Started RPC server';
|
message: "Started RPC server";
|
||||||
addr: string;
|
addr: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -41,12 +41,12 @@ export interface CliLogStartedRpcServer extends CliLog {
|
||||||
export function isCliLogStartedRpcServer(
|
export function isCliLogStartedRpcServer(
|
||||||
log: CliLog,
|
log: CliLog,
|
||||||
): log is CliLogStartedRpcServer {
|
): log is CliLogStartedRpcServer {
|
||||||
return log.fields.message === 'Started RPC server';
|
return log.fields.message === "Started RPC server";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CliLogReleasingSwapLockLog extends CliLog {
|
export interface CliLogReleasingSwapLockLog extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'Releasing swap lock';
|
message: "Releasing swap lock";
|
||||||
swap_id: string;
|
swap_id: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -54,23 +54,23 @@ export interface CliLogReleasingSwapLockLog extends CliLog {
|
||||||
export function isCliLogReleasingSwapLockLog(
|
export function isCliLogReleasingSwapLockLog(
|
||||||
log: CliLog,
|
log: CliLog,
|
||||||
): log is CliLogReleasingSwapLockLog {
|
): log is CliLogReleasingSwapLockLog {
|
||||||
return log.fields.message === 'Releasing swap lock';
|
return log.fields.message === "Releasing swap lock";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CliLogApiCallError extends CliLog {
|
export interface CliLogApiCallError extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'API call resulted in an error';
|
message: "API call resulted in an error";
|
||||||
err: string;
|
err: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isCliLogApiCallError(log: CliLog): log is CliLogApiCallError {
|
export function isCliLogApiCallError(log: CliLog): log is CliLogApiCallError {
|
||||||
return log.fields.message === 'API call resulted in an error';
|
return log.fields.message === "API call resulted in an error";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CliLogAcquiringSwapLockLog extends CliLog {
|
export interface CliLogAcquiringSwapLockLog extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'Acquiring swap lock';
|
message: "Acquiring swap lock";
|
||||||
swap_id: string;
|
swap_id: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -78,12 +78,12 @@ export interface CliLogAcquiringSwapLockLog extends CliLog {
|
||||||
export function isCliLogAcquiringSwapLockLog(
|
export function isCliLogAcquiringSwapLockLog(
|
||||||
log: CliLog,
|
log: CliLog,
|
||||||
): log is CliLogAcquiringSwapLockLog {
|
): log is CliLogAcquiringSwapLockLog {
|
||||||
return log.fields.message === 'Acquiring swap lock';
|
return log.fields.message === "Acquiring swap lock";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CliLogReceivedQuote extends CliLog {
|
export interface CliLogReceivedQuote extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'Received quote';
|
message: "Received quote";
|
||||||
price: string;
|
price: string;
|
||||||
minimum_amount: string;
|
minimum_amount: string;
|
||||||
maximum_amount: string;
|
maximum_amount: string;
|
||||||
|
@ -91,12 +91,12 @@ export interface CliLogReceivedQuote extends CliLog {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isCliLogReceivedQuote(log: CliLog): log is CliLogReceivedQuote {
|
export function isCliLogReceivedQuote(log: CliLog): log is CliLogReceivedQuote {
|
||||||
return log.fields.message === 'Received quote';
|
return log.fields.message === "Received quote";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CliLogWaitingForBtcDeposit extends CliLog {
|
export interface CliLogWaitingForBtcDeposit extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'Waiting for Bitcoin deposit';
|
message: "Waiting for Bitcoin deposit";
|
||||||
deposit_address: string;
|
deposit_address: string;
|
||||||
min_deposit_until_swap_will_start: string;
|
min_deposit_until_swap_will_start: string;
|
||||||
max_deposit_until_maximum_amount_is_reached: string;
|
max_deposit_until_maximum_amount_is_reached: string;
|
||||||
|
@ -111,24 +111,24 @@ export interface CliLogWaitingForBtcDeposit extends CliLog {
|
||||||
export function isCliLogWaitingForBtcDeposit(
|
export function isCliLogWaitingForBtcDeposit(
|
||||||
log: CliLog,
|
log: CliLog,
|
||||||
): log is CliLogWaitingForBtcDeposit {
|
): log is CliLogWaitingForBtcDeposit {
|
||||||
return log.fields.message === 'Waiting for Bitcoin deposit';
|
return log.fields.message === "Waiting for Bitcoin deposit";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CliLogReceivedBtc extends CliLog {
|
export interface CliLogReceivedBtc extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'Received Bitcoin';
|
message: "Received Bitcoin";
|
||||||
max_giveable: string;
|
max_giveable: string;
|
||||||
new_balance: string;
|
new_balance: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isCliLogReceivedBtc(log: CliLog): log is CliLogReceivedBtc {
|
export function isCliLogReceivedBtc(log: CliLog): log is CliLogReceivedBtc {
|
||||||
return log.fields.message === 'Received Bitcoin';
|
return log.fields.message === "Received Bitcoin";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CliLogDeterminedSwapAmount extends CliLog {
|
export interface CliLogDeterminedSwapAmount extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'Determined swap amount';
|
message: "Determined swap amount";
|
||||||
amount: string;
|
amount: string;
|
||||||
fees: string;
|
fees: string;
|
||||||
};
|
};
|
||||||
|
@ -137,49 +137,49 @@ export interface CliLogDeterminedSwapAmount extends CliLog {
|
||||||
export function isCliLogDeterminedSwapAmount(
|
export function isCliLogDeterminedSwapAmount(
|
||||||
log: CliLog,
|
log: CliLog,
|
||||||
): log is CliLogDeterminedSwapAmount {
|
): log is CliLogDeterminedSwapAmount {
|
||||||
return log.fields.message === 'Determined swap amount';
|
return log.fields.message === "Determined swap amount";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CliLogStartedSwap extends CliLog {
|
export interface CliLogStartedSwap extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'Starting new swap';
|
message: "Starting new swap";
|
||||||
swap_id: string;
|
swap_id: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isCliLogStartedSwap(log: CliLog): log is CliLogStartedSwap {
|
export function isCliLogStartedSwap(log: CliLog): log is CliLogStartedSwap {
|
||||||
return log.fields.message === 'Starting new swap';
|
return log.fields.message === "Starting new swap";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CliLogPublishedBtcTx extends CliLog {
|
export interface CliLogPublishedBtcTx extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'Published Bitcoin transaction';
|
message: "Published Bitcoin transaction";
|
||||||
txid: string;
|
txid: string;
|
||||||
kind: 'lock' | 'cancel' | 'withdraw' | 'refund';
|
kind: "lock" | "cancel" | "withdraw" | "refund";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isCliLogPublishedBtcTx(
|
export function isCliLogPublishedBtcTx(
|
||||||
log: CliLog,
|
log: CliLog,
|
||||||
): log is CliLogPublishedBtcTx {
|
): log is CliLogPublishedBtcTx {
|
||||||
return log.fields.message === 'Published Bitcoin transaction';
|
return log.fields.message === "Published Bitcoin transaction";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CliLogBtcTxFound extends CliLog {
|
export interface CliLogBtcTxFound extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'Found relevant Bitcoin transaction';
|
message: "Found relevant Bitcoin transaction";
|
||||||
txid: string;
|
txid: string;
|
||||||
status: string;
|
status: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isCliLogBtcTxFound(log: CliLog): log is CliLogBtcTxFound {
|
export function isCliLogBtcTxFound(log: CliLog): log is CliLogBtcTxFound {
|
||||||
return log.fields.message === 'Found relevant Bitcoin transaction';
|
return log.fields.message === "Found relevant Bitcoin transaction";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CliLogBtcTxStatusChanged extends CliLog {
|
export interface CliLogBtcTxStatusChanged extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'Bitcoin transaction status changed';
|
message: "Bitcoin transaction status changed";
|
||||||
txid: string;
|
txid: string;
|
||||||
new_status: string;
|
new_status: string;
|
||||||
};
|
};
|
||||||
|
@ -188,12 +188,12 @@ export interface CliLogBtcTxStatusChanged extends CliLog {
|
||||||
export function isCliLogBtcTxStatusChanged(
|
export function isCliLogBtcTxStatusChanged(
|
||||||
log: CliLog,
|
log: CliLog,
|
||||||
): log is CliLogBtcTxStatusChanged {
|
): log is CliLogBtcTxStatusChanged {
|
||||||
return log.fields.message === 'Bitcoin transaction status changed';
|
return log.fields.message === "Bitcoin transaction status changed";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CliLogAliceLockedXmr extends CliLog {
|
export interface CliLogAliceLockedXmr extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'Alice locked Monero';
|
message: "Alice locked Monero";
|
||||||
txid: string;
|
txid: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -201,12 +201,12 @@ export interface CliLogAliceLockedXmr extends CliLog {
|
||||||
export function isCliLogAliceLockedXmr(
|
export function isCliLogAliceLockedXmr(
|
||||||
log: CliLog,
|
log: CliLog,
|
||||||
): log is CliLogAliceLockedXmr {
|
): log is CliLogAliceLockedXmr {
|
||||||
return log.fields.message === 'Alice locked Monero';
|
return log.fields.message === "Alice locked Monero";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CliLogReceivedXmrLockTxConfirmation extends CliLog {
|
export interface CliLogReceivedXmrLockTxConfirmation extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'Received new confirmation for Monero lock tx';
|
message: "Received new confirmation for Monero lock tx";
|
||||||
txid: string;
|
txid: string;
|
||||||
seen_confirmations: string;
|
seen_confirmations: string;
|
||||||
needed_confirmations: string;
|
needed_confirmations: string;
|
||||||
|
@ -216,50 +216,50 @@ export interface CliLogReceivedXmrLockTxConfirmation extends CliLog {
|
||||||
export function isCliLogReceivedXmrLockTxConfirmation(
|
export function isCliLogReceivedXmrLockTxConfirmation(
|
||||||
log: CliLog,
|
log: CliLog,
|
||||||
): log is CliLogReceivedXmrLockTxConfirmation {
|
): log is CliLogReceivedXmrLockTxConfirmation {
|
||||||
return log.fields.message === 'Received new confirmation for Monero lock tx';
|
return log.fields.message === "Received new confirmation for Monero lock tx";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CliLogAdvancingState extends CliLog {
|
export interface CliLogAdvancingState extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'Advancing state';
|
message: "Advancing state";
|
||||||
state:
|
state:
|
||||||
| 'quote has been requested'
|
| "quote has been requested"
|
||||||
| 'execution setup done'
|
| "execution setup done"
|
||||||
| 'btc is locked'
|
| "btc is locked"
|
||||||
| 'XMR lock transaction transfer proof received'
|
| "XMR lock transaction transfer proof received"
|
||||||
| 'xmr is locked'
|
| "xmr is locked"
|
||||||
| 'encrypted signature is sent'
|
| "encrypted signature is sent"
|
||||||
| 'btc is redeemed'
|
| "btc is redeemed"
|
||||||
| 'cancel timelock is expired'
|
| "cancel timelock is expired"
|
||||||
| 'btc is cancelled'
|
| "btc is cancelled"
|
||||||
| 'btc is refunded'
|
| "btc is refunded"
|
||||||
| 'xmr is redeemed'
|
| "xmr is redeemed"
|
||||||
| 'btc is punished'
|
| "btc is punished"
|
||||||
| 'safely aborted';
|
| "safely aborted";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isCliLogAdvancingState(
|
export function isCliLogAdvancingState(
|
||||||
log: CliLog,
|
log: CliLog,
|
||||||
): log is CliLogAdvancingState {
|
): log is CliLogAdvancingState {
|
||||||
return log.fields.message === 'Advancing state';
|
return log.fields.message === "Advancing state";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CliLogRedeemedXmr extends CliLog {
|
export interface CliLogRedeemedXmr extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'Successfully transferred XMR to wallet';
|
message: "Successfully transferred XMR to wallet";
|
||||||
monero_receive_address: string;
|
monero_receive_address: string;
|
||||||
txid: string;
|
txid: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isCliLogRedeemedXmr(log: CliLog): log is CliLogRedeemedXmr {
|
export function isCliLogRedeemedXmr(log: CliLog): log is CliLogRedeemedXmr {
|
||||||
return log.fields.message === 'Successfully transferred XMR to wallet';
|
return log.fields.message === "Successfully transferred XMR to wallet";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface YouHaveBeenPunishedCliLog extends CliLog {
|
export interface YouHaveBeenPunishedCliLog extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'You have been punished for not refunding in time';
|
message: "You have been punished for not refunding in time";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,7 +267,7 @@ export function isYouHaveBeenPunishedCliLog(
|
||||||
log: CliLog,
|
log: CliLog,
|
||||||
): log is YouHaveBeenPunishedCliLog {
|
): log is YouHaveBeenPunishedCliLog {
|
||||||
return (
|
return (
|
||||||
log.fields.message === 'You have been punished for not refunding in time'
|
log.fields.message === "You have been punished for not refunding in time"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,14 +280,14 @@ function getCliLogSpanAttribute<T>(log: CliLog, key: string): T | null {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCliLogSpanSwapId(log: CliLog): string | null {
|
export function getCliLogSpanSwapId(log: CliLog): string | null {
|
||||||
return getCliLogSpanAttribute<string>(log, 'swap_id');
|
return getCliLogSpanAttribute<string>(log, "swap_id");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCliLogSpanLogReferenceId(log: CliLog): string | null {
|
export function getCliLogSpanLogReferenceId(log: CliLog): string | null {
|
||||||
return (
|
return (
|
||||||
getCliLogSpanAttribute<string>(log, 'log_reference_id')?.replace(
|
getCliLogSpanAttribute<string>(log, "log_reference_id")?.replace(
|
||||||
/"/g,
|
/"/g,
|
||||||
'',
|
"",
|
||||||
) || null
|
) || null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -301,7 +301,7 @@ export function hasCliLogOneOfMultipleSpans(
|
||||||
|
|
||||||
export interface CliLogStartedSyncingMoneroWallet extends CliLog {
|
export interface CliLogStartedSyncingMoneroWallet extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'Syncing Monero wallet';
|
message: "Syncing Monero wallet";
|
||||||
current_sync_height?: boolean;
|
current_sync_height?: boolean;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -309,18 +309,18 @@ export interface CliLogStartedSyncingMoneroWallet extends CliLog {
|
||||||
export function isCliLogStartedSyncingMoneroWallet(
|
export function isCliLogStartedSyncingMoneroWallet(
|
||||||
log: CliLog,
|
log: CliLog,
|
||||||
): log is CliLogStartedSyncingMoneroWallet {
|
): log is CliLogStartedSyncingMoneroWallet {
|
||||||
return log.fields.message === 'Syncing Monero wallet';
|
return log.fields.message === "Syncing Monero wallet";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CliLogFinishedSyncingMoneroWallet extends CliLog {
|
export interface CliLogFinishedSyncingMoneroWallet extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'Synced Monero wallet';
|
message: "Synced Monero wallet";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CliLogFailedToSyncMoneroWallet extends CliLog {
|
export interface CliLogFailedToSyncMoneroWallet extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'Failed to sync Monero wallet';
|
message: "Failed to sync Monero wallet";
|
||||||
error: string;
|
error: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -328,18 +328,18 @@ export interface CliLogFailedToSyncMoneroWallet extends CliLog {
|
||||||
export function isCliLogFailedToSyncMoneroWallet(
|
export function isCliLogFailedToSyncMoneroWallet(
|
||||||
log: CliLog,
|
log: CliLog,
|
||||||
): log is CliLogFailedToSyncMoneroWallet {
|
): log is CliLogFailedToSyncMoneroWallet {
|
||||||
return log.fields.message === 'Failed to sync Monero wallet';
|
return log.fields.message === "Failed to sync Monero wallet";
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isCliLogFinishedSyncingMoneroWallet(
|
export function isCliLogFinishedSyncingMoneroWallet(
|
||||||
log: CliLog,
|
log: CliLog,
|
||||||
): log is CliLogFinishedSyncingMoneroWallet {
|
): log is CliLogFinishedSyncingMoneroWallet {
|
||||||
return log.fields.message === 'Monero wallet synced';
|
return log.fields.message === "Monero wallet synced";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CliLogDownloadingMoneroWalletRpc extends CliLog {
|
export interface CliLogDownloadingMoneroWalletRpc extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'Downloading monero-wallet-rpc';
|
message: "Downloading monero-wallet-rpc";
|
||||||
progress: string;
|
progress: string;
|
||||||
size: string;
|
size: string;
|
||||||
download_url: string;
|
download_url: string;
|
||||||
|
@ -349,19 +349,19 @@ export interface CliLogDownloadingMoneroWalletRpc extends CliLog {
|
||||||
export function isCliLogDownloadingMoneroWalletRpc(
|
export function isCliLogDownloadingMoneroWalletRpc(
|
||||||
log: CliLog,
|
log: CliLog,
|
||||||
): log is CliLogDownloadingMoneroWalletRpc {
|
): log is CliLogDownloadingMoneroWalletRpc {
|
||||||
return log.fields.message === 'Downloading monero-wallet-rpc';
|
return log.fields.message === "Downloading monero-wallet-rpc";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CliLogStartedSyncingMoneroWallet extends CliLog {
|
export interface CliLogStartedSyncingMoneroWallet extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'Syncing Monero wallet';
|
message: "Syncing Monero wallet";
|
||||||
current_sync_height?: boolean;
|
current_sync_height?: boolean;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CliLogDownloadingMoneroWalletRpc extends CliLog {
|
export interface CliLogDownloadingMoneroWalletRpc extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'Downloading monero-wallet-rpc';
|
message: "Downloading monero-wallet-rpc";
|
||||||
progress: string;
|
progress: string;
|
||||||
size: string;
|
size: string;
|
||||||
download_url: string;
|
download_url: string;
|
||||||
|
@ -370,7 +370,7 @@ export interface CliLogDownloadingMoneroWalletRpc extends CliLog {
|
||||||
|
|
||||||
export interface CliLogGotNotificationForNewBlock extends CliLog {
|
export interface CliLogGotNotificationForNewBlock extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'Got notification for new block';
|
message: "Got notification for new block";
|
||||||
block_height: string;
|
block_height: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -378,29 +378,36 @@ export interface CliLogGotNotificationForNewBlock extends CliLog {
|
||||||
export function isCliLogGotNotificationForNewBlock(
|
export function isCliLogGotNotificationForNewBlock(
|
||||||
log: CliLog,
|
log: CliLog,
|
||||||
): log is CliLogGotNotificationForNewBlock {
|
): log is CliLogGotNotificationForNewBlock {
|
||||||
return log.fields.message === 'Got notification for new block';
|
return log.fields.message === "Got notification for new block";
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CliLogAttemptingToCooperativelyRedeemXmr extends CliLog {
|
export interface CliLogAttemptingToCooperativelyRedeemXmr extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'Attempting to cooperatively redeem XMR after being punished';
|
message: "Attempting to cooperatively redeem XMR after being punished";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isCliLogAttemptingToCooperativelyRedeemXmr(
|
export function isCliLogAttemptingToCooperativelyRedeemXmr(
|
||||||
log: CliLog,
|
log: CliLog,
|
||||||
): log is CliLogAttemptingToCooperativelyRedeemXmr {
|
): log is CliLogAttemptingToCooperativelyRedeemXmr {
|
||||||
return log.fields.message === 'Attempting to cooperatively redeem XMR after being punished';
|
return (
|
||||||
|
log.fields.message ===
|
||||||
|
"Attempting to cooperatively redeem XMR after being punished"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CliLogAliceHasAcceptedOurRequestToCooperativelyRedeemTheXmr extends CliLog {
|
export interface CliLogAliceHasAcceptedOurRequestToCooperativelyRedeemTheXmr
|
||||||
|
extends CliLog {
|
||||||
fields: {
|
fields: {
|
||||||
message: 'Alice has accepted our request to cooperatively redeem the XMR';
|
message: "Alice has accepted our request to cooperatively redeem the XMR";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isCliLogAliceHasAcceptedOurRequestToCooperativelyRedeemTheXmr(
|
export function isCliLogAliceHasAcceptedOurRequestToCooperativelyRedeemTheXmr(
|
||||||
log: CliLog,
|
log: CliLog,
|
||||||
): log is CliLogAliceHasAcceptedOurRequestToCooperativelyRedeemTheXmr {
|
): log is CliLogAliceHasAcceptedOurRequestToCooperativelyRedeemTheXmr {
|
||||||
return log.fields.message === 'Alice has accepted our request to cooperatively redeem the XMR';
|
return (
|
||||||
|
log.fields.message ===
|
||||||
|
"Alice has accepted our request to cooperatively redeem the XMR"
|
||||||
|
);
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
import { CliLog, SwapSpawnType } from './cliModel';
|
import { CliLog, SwapSpawnType } from "./cliModel";
|
||||||
import { Provider } from './apiModel';
|
import { Provider } from "./apiModel";
|
||||||
|
|
||||||
export interface SwapSlice {
|
export interface SwapSlice {
|
||||||
state: SwapState | null;
|
state: SwapState | null;
|
||||||
|
@ -20,21 +20,21 @@ export interface SwapState {
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum SwapStateType {
|
export enum SwapStateType {
|
||||||
INITIATED = 'initiated',
|
INITIATED = "initiated",
|
||||||
RECEIVED_QUOTE = 'received quote',
|
RECEIVED_QUOTE = "received quote",
|
||||||
WAITING_FOR_BTC_DEPOSIT = 'waiting for btc deposit',
|
WAITING_FOR_BTC_DEPOSIT = "waiting for btc deposit",
|
||||||
STARTED = 'started',
|
STARTED = "started",
|
||||||
BTC_LOCK_TX_IN_MEMPOOL = 'btc lock tx is in mempool',
|
BTC_LOCK_TX_IN_MEMPOOL = "btc lock tx is in mempool",
|
||||||
XMR_LOCK_TX_IN_MEMPOOL = 'xmr lock tx is in mempool',
|
XMR_LOCK_TX_IN_MEMPOOL = "xmr lock tx is in mempool",
|
||||||
XMR_LOCKED = 'xmr is locked',
|
XMR_LOCKED = "xmr is locked",
|
||||||
BTC_REDEEMED = 'btc redeemed',
|
BTC_REDEEMED = "btc redeemed",
|
||||||
XMR_REDEEM_IN_MEMPOOL = 'xmr redeem tx is in mempool',
|
XMR_REDEEM_IN_MEMPOOL = "xmr redeem tx is in mempool",
|
||||||
PROCESS_EXITED = 'process exited',
|
PROCESS_EXITED = "process exited",
|
||||||
BTC_CANCELLED = 'btc cancelled',
|
BTC_CANCELLED = "btc cancelled",
|
||||||
BTC_REFUNDED = 'btc refunded',
|
BTC_REFUNDED = "btc refunded",
|
||||||
BTC_PUNISHED = 'btc punished',
|
BTC_PUNISHED = "btc punished",
|
||||||
ATTEMPTING_COOPERATIVE_REDEEM = 'attempting cooperative redeem',
|
ATTEMPTING_COOPERATIVE_REDEEM = "attempting cooperative redeem",
|
||||||
COOPERATIVE_REDEEM_REJECTED = 'cooperative redeem rejected',
|
COOPERATIVE_REDEEM_REJECTED = "cooperative redeem rejected",
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isSwapState(state?: SwapState | null): state is SwapState {
|
export function isSwapState(state?: SwapState | null): state is SwapState {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Alert, ExtendedProviderStatus } from 'models/apiModel';
|
import { Alert, ExtendedProviderStatus } from "models/apiModel";
|
||||||
|
|
||||||
const API_BASE_URL = 'https://api.unstoppableswap.net';
|
const API_BASE_URL = "https://api.unstoppableswap.net";
|
||||||
|
|
||||||
export async function fetchProvidersViaHttp(): Promise<
|
export async function fetchProvidersViaHttp(): Promise<
|
||||||
ExtendedProviderStatus[]
|
ExtendedProviderStatus[]
|
||||||
|
@ -23,9 +23,9 @@ export async function submitFeedbackViaHttp(
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await fetch(`${API_BASE_URL}/api/submit-feedback`, {
|
const response = await fetch(`${API_BASE_URL}/api/submit-feedback`, {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ body, attachedData }),
|
body: JSON.stringify({ body, attachedData }),
|
||||||
});
|
});
|
||||||
|
@ -53,9 +53,9 @@ async function fetchCurrencyUsdPrice(currency: string): Promise<number> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchBtcPrice(): Promise<number> {
|
export async function fetchBtcPrice(): Promise<number> {
|
||||||
return fetchCurrencyUsdPrice('bitcoin');
|
return fetchCurrencyUsdPrice("bitcoin");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchXmrPrice(): Promise<number> {
|
export async function fetchXmrPrice(): Promise<number> {
|
||||||
return fetchCurrencyUsdPrice('monero');
|
return fetchCurrencyUsdPrice("monero");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { Box, makeStyles, CssBaseline } from '@material-ui/core';
|
import { Box, makeStyles, CssBaseline } from "@material-ui/core";
|
||||||
import { createTheme, ThemeProvider } from '@material-ui/core/styles';
|
import { createTheme, ThemeProvider } from "@material-ui/core/styles";
|
||||||
import { indigo } from '@material-ui/core/colors';
|
import { indigo } from "@material-ui/core/colors";
|
||||||
import { MemoryRouter as Router, Routes, Route } from 'react-router-dom';
|
import { MemoryRouter as Router, Routes, Route } from "react-router-dom";
|
||||||
import Navigation, { drawerWidth } from './navigation/Navigation';
|
import Navigation, { drawerWidth } from "./navigation/Navigation";
|
||||||
import HistoryPage from './pages/history/HistoryPage';
|
import HistoryPage from "./pages/history/HistoryPage";
|
||||||
import SwapPage from './pages/swap/SwapPage';
|
import SwapPage from "./pages/swap/SwapPage";
|
||||||
import WalletPage from './pages/wallet/WalletPage';
|
import WalletPage from "./pages/wallet/WalletPage";
|
||||||
import HelpPage from './pages/help/HelpPage';
|
import HelpPage from "./pages/help/HelpPage";
|
||||||
import GlobalSnackbarProvider from './snackbar/GlobalSnackbarProvider';
|
import GlobalSnackbarProvider from "./snackbar/GlobalSnackbarProvider";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
innerContent: {
|
innerContent: {
|
||||||
|
@ -20,14 +20,14 @@ const useStyles = makeStyles((theme) => ({
|
||||||
|
|
||||||
const theme = createTheme({
|
const theme = createTheme({
|
||||||
palette: {
|
palette: {
|
||||||
type: 'dark',
|
type: "dark",
|
||||||
primary: {
|
primary: {
|
||||||
main: '#f4511e',
|
main: "#f4511e",
|
||||||
},
|
},
|
||||||
secondary: indigo,
|
secondary: indigo,
|
||||||
},
|
},
|
||||||
transitions: {
|
transitions: {
|
||||||
create: () => 'none',
|
create: () => "none",
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
MuiButtonBase: {
|
MuiButtonBase: {
|
||||||
|
|
|
@ -4,12 +4,12 @@ import {
|
||||||
CircularProgress,
|
CircularProgress,
|
||||||
IconButton,
|
IconButton,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from '@material-ui/core';
|
} from "@material-ui/core";
|
||||||
import { ReactElement, ReactNode, useEffect, useState } from 'react';
|
import { ReactElement, ReactNode, useEffect, useState } from "react";
|
||||||
import { useSnackbar } from 'notistack';
|
import { useSnackbar } from "notistack";
|
||||||
import { useAppSelector } from 'store/hooks';
|
import { useAppSelector } from "store/hooks";
|
||||||
import { RpcProcessStateType } from 'models/rpcModel';
|
import { RpcProcessStateType } from "models/rpcModel";
|
||||||
import { isExternalRpc } from 'store/config';
|
import { isExternalRpc } from "store/config";
|
||||||
|
|
||||||
function IpcButtonTooltip({
|
function IpcButtonTooltip({
|
||||||
requiresRpcAndNotReady,
|
requiresRpcAndNotReady,
|
||||||
|
@ -27,19 +27,19 @@ function IpcButtonTooltip({
|
||||||
}
|
}
|
||||||
|
|
||||||
const getMessage = () => {
|
const getMessage = () => {
|
||||||
if (!requiresRpcAndNotReady) return '';
|
if (!requiresRpcAndNotReady) return "";
|
||||||
|
|
||||||
switch (processType) {
|
switch (processType) {
|
||||||
case RpcProcessStateType.LISTENING_FOR_CONNECTIONS:
|
case RpcProcessStateType.LISTENING_FOR_CONNECTIONS:
|
||||||
return '';
|
return "";
|
||||||
case RpcProcessStateType.STARTED:
|
case RpcProcessStateType.STARTED:
|
||||||
return 'Cannot execute this action because the Swap Daemon is still starting and not yet ready to accept connections. Please wait a moment and try again';
|
return "Cannot execute this action because the Swap Daemon is still starting and not yet ready to accept connections. Please wait a moment and try again";
|
||||||
case RpcProcessStateType.EXITED:
|
case RpcProcessStateType.EXITED:
|
||||||
return 'Cannot execute this action because the Swap Daemon has been stopped. Please start the Swap Daemon again to continue';
|
return "Cannot execute this action because the Swap Daemon has been stopped. Please start the Swap Daemon again to continue";
|
||||||
case RpcProcessStateType.NOT_STARTED:
|
case RpcProcessStateType.NOT_STARTED:
|
||||||
return 'Cannot execute this action because the Swap Daemon has not been started yet. Please start the Swap Daemon first';
|
return "Cannot execute this action because the Swap Daemon has not been started yet. Please start the Swap Daemon first";
|
||||||
default:
|
default:
|
||||||
return '';
|
return "";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -108,13 +108,13 @@ export default function IpcInvokeButton<T>({
|
||||||
setIsPending(true);
|
setIsPending(true);
|
||||||
try {
|
try {
|
||||||
// const result = await ipcRenderer.invoke(ipcChannel, ...ipcArgs);
|
// const result = await ipcRenderer.invoke(ipcChannel, ...ipcArgs);
|
||||||
throw new Error('Not implemented');
|
throw new Error("Not implemented");
|
||||||
// onSuccess?.(result);
|
// onSuccess?.(result);
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
if (displayErrorSnackbar) {
|
if (displayErrorSnackbar) {
|
||||||
enqueueSnackbar((e as Error).message, {
|
enqueueSnackbar((e as Error).message, {
|
||||||
autoHideDuration: 60 * 1000,
|
autoHideDuration: 60 * 1000,
|
||||||
variant: 'error',
|
variant: "error",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { ReactNode, useEffect, useState } from "react";
|
||||||
interface IpcInvokeButtonProps<T> {
|
interface IpcInvokeButtonProps<T> {
|
||||||
onSuccess?: (data: T) => void;
|
onSuccess?: (data: T) => void;
|
||||||
onClick: () => Promise<T>;
|
onClick: () => Promise<T>;
|
||||||
onPendingChange?: (bool) => void;
|
onPendingChange?: (isPending: boolean) => void;
|
||||||
isLoadingOverride?: boolean;
|
isLoadingOverride?: boolean;
|
||||||
isIconButton?: boolean;
|
isIconButton?: boolean;
|
||||||
loadIcon?: ReactNode;
|
loadIcon?: ReactNode;
|
||||||
|
@ -46,7 +46,7 @@ export default function PromiseInvokeButton<T>({
|
||||||
onSuccess?.(result);
|
onSuccess?.(result);
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
if (displayErrorSnackbar) {
|
if (displayErrorSnackbar) {
|
||||||
enqueueSnackbar((e as Error).message, {
|
enqueueSnackbar(e as String, {
|
||||||
autoHideDuration: 60 * 1000,
|
autoHideDuration: 60 * 1000,
|
||||||
variant: "error",
|
variant: "error",
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Button } from '@material-ui/core';
|
import { Button } from "@material-ui/core";
|
||||||
import Alert from '@material-ui/lab/Alert';
|
import Alert from "@material-ui/lab/Alert";
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from "react-router-dom";
|
||||||
import { useAppSelector } from 'store/hooks';
|
import { useAppSelector } from "store/hooks";
|
||||||
|
|
||||||
export default function FundsLeftInWalletAlert() {
|
export default function FundsLeftInWalletAlert() {
|
||||||
const fundsLeft = useAppSelector((state) => state.rpc.state.balance);
|
const fundsLeft = useAppSelector((state) => state.rpc.state.balance);
|
||||||
|
@ -16,7 +16,7 @@ export default function FundsLeftInWalletAlert() {
|
||||||
<Button
|
<Button
|
||||||
color="inherit"
|
color="inherit"
|
||||||
size="small"
|
size="small"
|
||||||
onClick={() => navigate('/wallet')}
|
onClick={() => navigate("/wallet")}
|
||||||
>
|
>
|
||||||
View
|
View
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Alert } from '@material-ui/lab';
|
import { Alert } from "@material-ui/lab";
|
||||||
import { Box, LinearProgress } from '@material-ui/core';
|
import { Box, LinearProgress } from "@material-ui/core";
|
||||||
import { useAppSelector } from 'store/hooks';
|
import { useAppSelector } from "store/hooks";
|
||||||
|
|
||||||
export default function MoneroWalletRpcUpdatingAlert() {
|
export default function MoneroWalletRpcUpdatingAlert() {
|
||||||
const updateState = useAppSelector(
|
const updateState = useAppSelector(
|
||||||
|
@ -17,7 +17,7 @@ export default function MoneroWalletRpcUpdatingAlert() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Alert severity="info">
|
<Alert severity="info">
|
||||||
<Box style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
|
<Box style={{ display: "flex", flexDirection: "column", gap: "0.5rem" }}>
|
||||||
<span>The Monero wallet is updating. This may take a few moments</span>
|
<span>The Monero wallet is updating. This may take a few moments</span>
|
||||||
<LinearProgress
|
<LinearProgress
|
||||||
variant="determinate"
|
variant="determinate"
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { Alert } from '@material-ui/lab';
|
import { Alert } from "@material-ui/lab";
|
||||||
import { Box, makeStyles } from '@material-ui/core';
|
import { Box, makeStyles } from "@material-ui/core";
|
||||||
import { useAppSelector } from 'store/hooks';
|
import { useAppSelector } from "store/hooks";
|
||||||
import WalletRefreshButton from '../pages/wallet/WalletRefreshButton';
|
import WalletRefreshButton from "../pages/wallet/WalletRefreshButton";
|
||||||
import { SatsAmount } from '../other/Units';
|
import { SatsAmount } from "../other/Units";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
outer: {
|
outer: {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Alert } from '@material-ui/lab';
|
import { Alert } from "@material-ui/lab";
|
||||||
import { CircularProgress } from '@material-ui/core';
|
import { CircularProgress } from "@material-ui/core";
|
||||||
import { useAppSelector } from 'store/hooks';
|
import { useAppSelector } from "store/hooks";
|
||||||
import { RpcProcessStateType } from 'models/rpcModel';
|
import { RpcProcessStateType } from "models/rpcModel";
|
||||||
|
|
||||||
export default function RpcStatusAlert() {
|
export default function RpcStatusAlert() {
|
||||||
const rpcProcess = useAppSelector((s) => s.rpc.process);
|
const rpcProcess = useAppSelector((s) => s.rpc.process);
|
||||||
|
|
|
@ -38,21 +38,20 @@ export default function SwapMightBeCancelledAlert({
|
||||||
return (
|
return (
|
||||||
<Alert severity="warning" className={classes.outer} variant="filled">
|
<Alert severity="warning" className={classes.outer} variant="filled">
|
||||||
<AlertTitle>Be careful!</AlertTitle>
|
<AlertTitle>Be careful!</AlertTitle>
|
||||||
The swap provider has taken a long time to lock their Monero. This
|
The swap provider has taken a long time to lock their Monero. This might
|
||||||
might mean that:
|
mean that:
|
||||||
<ul className={classes.list}>
|
<ul className={classes.list}>
|
||||||
<li>
|
<li>
|
||||||
There is a technical issue that prevents them from locking
|
There is a technical issue that prevents them from locking their funds
|
||||||
their funds
|
|
||||||
</li>
|
</li>
|
||||||
<li>They are a malicious actor (unlikely)</li>
|
<li>They are a malicious actor (unlikely)</li>
|
||||||
</ul>
|
</ul>
|
||||||
<br />
|
<br />
|
||||||
There is still hope for the swap to be successful but you have to be
|
There is still hope for the swap to be successful but you have to be extra
|
||||||
extra careful. Regardless of why it has taken them so long, it is
|
careful. Regardless of why it has taken them so long, it is important that
|
||||||
important that you refund the swap within the required time period
|
you refund the swap within the required time period if the swap is not
|
||||||
if the swap is not completed. If you fail to to do so, you will be
|
completed. If you fail to to do so, you will be punished and lose your
|
||||||
punished and lose your money.
|
money.
|
||||||
<ul className={classes.list}>
|
<ul className={classes.list}>
|
||||||
{isSwapTimelockInfoNone(timelock) && (
|
{isSwapTimelockInfoNone(timelock) && (
|
||||||
<>
|
<>
|
||||||
|
@ -67,13 +66,9 @@ export default function SwapMightBeCancelledAlert({
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<strong>
|
<strong>
|
||||||
If you have not refunded or completed the swap
|
If you have not refunded or completed the swap in about{" "}
|
||||||
in about{" "}
|
|
||||||
<HumanizedBitcoinBlockDuration
|
<HumanizedBitcoinBlockDuration
|
||||||
blocks={
|
blocks={timelock.None.blocks_left + punishTimelockOffset}
|
||||||
timelock.None.blocks_left +
|
|
||||||
punishTimelockOffset
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
, you will lose your funds.
|
, you will lose your funds.
|
||||||
</strong>
|
</strong>
|
||||||
|
@ -83,8 +78,7 @@ export default function SwapMightBeCancelledAlert({
|
||||||
{isSwapTimelockInfoCancelled(timelock) && (
|
{isSwapTimelockInfoCancelled(timelock) && (
|
||||||
<li>
|
<li>
|
||||||
<strong>
|
<strong>
|
||||||
If you have not refunded or completed the swap in
|
If you have not refunded or completed the swap in about{" "}
|
||||||
about{" "}
|
|
||||||
<HumanizedBitcoinBlockDuration
|
<HumanizedBitcoinBlockDuration
|
||||||
blocks={timelock.Cancel.blocks_left}
|
blocks={timelock.Cancel.blocks_left}
|
||||||
/>
|
/>
|
||||||
|
@ -94,8 +88,8 @@ export default function SwapMightBeCancelledAlert({
|
||||||
)}
|
)}
|
||||||
<li>
|
<li>
|
||||||
As long as you see this screen, the swap will be refunded
|
As long as you see this screen, the swap will be refunded
|
||||||
automatically when the time comes. If this fails, you have
|
automatically when the time comes. If this fails, you have to manually
|
||||||
to manually refund by navigating to the History page.
|
refund by navigating to the History page.
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</Alert>
|
</Alert>
|
||||||
|
|
|
@ -66,11 +66,7 @@ const BitcoinRedeemedStateAlert = ({ swap }: { swap: GetSwapInfoResponse }) => {
|
||||||
"If this step fails, you can manually redeem the funds",
|
"If this step fails, you can manually redeem the funds",
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<SwapMoneroRecoveryButton
|
<SwapMoneroRecoveryButton swap={swap} size="small" variant="contained" />
|
||||||
swap={swap}
|
|
||||||
size="small"
|
|
||||||
variant="contained"
|
|
||||||
/>
|
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -91,16 +87,13 @@ const BitcoinLockedNoTimelockExpiredStateAlert = ({
|
||||||
<MessageList
|
<MessageList
|
||||||
messages={[
|
messages={[
|
||||||
<>
|
<>
|
||||||
Your Bitcoin is locked. If the swap is not completed in
|
Your Bitcoin is locked. If the swap is not completed in approximately{" "}
|
||||||
approximately{" "}
|
<HumanizedBitcoinBlockDuration blocks={timelock.None.blocks_left} />,
|
||||||
<HumanizedBitcoinBlockDuration
|
you need to refund
|
||||||
blocks={timelock.None.blocks_left}
|
|
||||||
/>
|
|
||||||
, you need to refund
|
|
||||||
</>,
|
</>,
|
||||||
<>
|
<>
|
||||||
You will lose your funds if you do not refund or complete the
|
You will lose your funds if you do not refund or complete the swap
|
||||||
swap within{" "}
|
within{" "}
|
||||||
<HumanizedBitcoinBlockDuration
|
<HumanizedBitcoinBlockDuration
|
||||||
blocks={timelock.None.blocks_left + punishTimelockOffset}
|
blocks={timelock.None.blocks_left + punishTimelockOffset}
|
||||||
/>
|
/>
|
||||||
|
@ -138,11 +131,7 @@ const BitcoinPossiblyCancelledAlert = ({
|
||||||
</>,
|
</>,
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<SwapCancelRefundButton
|
<SwapCancelRefundButton swap={swap} size="small" variant="contained" />
|
||||||
swap={swap}
|
|
||||||
size="small"
|
|
||||||
variant="contained"
|
|
||||||
/>
|
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Button } from '@material-ui/core';
|
import { Button } from "@material-ui/core";
|
||||||
import Alert from '@material-ui/lab/Alert';
|
import Alert from "@material-ui/lab/Alert";
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from "react-router-dom";
|
||||||
import { useResumeableSwapsCount } from 'store/hooks';
|
import { useResumeableSwapsCount } from "store/hooks";
|
||||||
|
|
||||||
export default function UnfinishedSwapsAlert() {
|
export default function UnfinishedSwapsAlert() {
|
||||||
const resumableSwapsCount = useResumeableSwapsCount();
|
const resumableSwapsCount = useResumeableSwapsCount();
|
||||||
|
@ -16,16 +16,16 @@ export default function UnfinishedSwapsAlert() {
|
||||||
<Button
|
<Button
|
||||||
color="inherit"
|
color="inherit"
|
||||||
size="small"
|
size="small"
|
||||||
onClick={() => navigate('/history')}
|
onClick={() => navigate("/history")}
|
||||||
>
|
>
|
||||||
VIEW
|
VIEW
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
You have{' '}
|
You have{" "}
|
||||||
{resumableSwapsCount > 1
|
{resumableSwapsCount > 1
|
||||||
? `${resumableSwapsCount} unfinished swaps`
|
? `${resumableSwapsCount} unfinished swaps`
|
||||||
: 'one unfinished swap'}
|
: "one unfinished swap"}
|
||||||
</Alert>
|
</Alert>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { SvgIcon } from '@material-ui/core';
|
import { SvgIcon } from "@material-ui/core";
|
||||||
import { SvgIconProps } from '@material-ui/core/SvgIcon/SvgIcon';
|
import { SvgIconProps } from "@material-ui/core/SvgIcon/SvgIcon";
|
||||||
|
|
||||||
export default function BitcoinIcon(props: SvgIconProps) {
|
export default function BitcoinIcon(props: SvgIconProps) {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { SvgIconProps } from '@material-ui/core/SvgIcon/SvgIcon';
|
import { SvgIconProps } from "@material-ui/core/SvgIcon/SvgIcon";
|
||||||
import { SvgIcon } from '@material-ui/core';
|
import { SvgIcon } from "@material-ui/core";
|
||||||
|
|
||||||
export default function DiscordIcon(props: SvgIconProps) {
|
export default function DiscordIcon(props: SvgIconProps) {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from "react";
|
||||||
import { IconButton } from '@material-ui/core';
|
import { IconButton } from "@material-ui/core";
|
||||||
|
|
||||||
export default function LinkIconButton({
|
export default function LinkIconButton({
|
||||||
url,
|
url,
|
||||||
|
@ -9,7 +9,7 @@ export default function LinkIconButton({
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<IconButton component="span" onClick={() => window.open(url, '_blank')}>
|
<IconButton component="span" onClick={() => window.open(url, "_blank")}>
|
||||||
{children}
|
{children}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { SvgIcon } from '@material-ui/core';
|
import { SvgIcon } from "@material-ui/core";
|
||||||
import { SvgIconProps } from '@material-ui/core/SvgIcon/SvgIcon';
|
import { SvgIconProps } from "@material-ui/core/SvgIcon/SvgIcon";
|
||||||
|
|
||||||
export default function MoneroIcon(props: SvgIconProps) {
|
export default function MoneroIcon(props: SvgIconProps) {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { SvgIcon } from '@material-ui/core';
|
import { SvgIcon } from "@material-ui/core";
|
||||||
import { SvgIconProps } from '@material-ui/core/SvgIcon/SvgIcon';
|
import { SvgIconProps } from "@material-ui/core/SvgIcon/SvgIcon";
|
||||||
|
|
||||||
export default function TorIcon(props: SvgIconProps) {
|
export default function TorIcon(props: SvgIconProps) {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from "react";
|
||||||
import { TextField } from '@material-ui/core';
|
import { TextField } from "@material-ui/core";
|
||||||
import { TextFieldProps } from '@material-ui/core/TextField/TextField';
|
import { TextFieldProps } from "@material-ui/core/TextField/TextField";
|
||||||
import { isBtcAddressValid } from 'utils/conversionUtils';
|
import { isBtcAddressValid } from "utils/conversionUtils";
|
||||||
import { isTestnet } from 'store/config';
|
import { isTestnet } from "store/config";
|
||||||
|
|
||||||
export default function BitcoinAddressTextField({
|
export default function BitcoinAddressTextField({
|
||||||
address,
|
address,
|
||||||
|
@ -16,11 +16,11 @@ export default function BitcoinAddressTextField({
|
||||||
onAddressValidityChange: (valid: boolean) => void;
|
onAddressValidityChange: (valid: boolean) => void;
|
||||||
helperText: string;
|
helperText: string;
|
||||||
} & TextFieldProps) {
|
} & TextFieldProps) {
|
||||||
const placeholder = isTestnet() ? 'tb1q4aelwalu...' : 'bc18ociqZ9mZ...';
|
const placeholder = isTestnet() ? "tb1q4aelwalu..." : "bc18ociqZ9mZ...";
|
||||||
const errorText = isBtcAddressValid(address, isTestnet())
|
const errorText = isBtcAddressValid(address, isTestnet())
|
||||||
? null
|
? null
|
||||||
: `Only bech32 addresses are supported. They begin with "${
|
: `Only bech32 addresses are supported. They begin with "${
|
||||||
isTestnet() ? 'tb1' : 'bc1'
|
isTestnet() ? "tb1" : "bc1"
|
||||||
}"`;
|
}"`;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from "react";
|
||||||
import { TextField } from '@material-ui/core';
|
import { TextField } from "@material-ui/core";
|
||||||
import { TextFieldProps } from '@material-ui/core/TextField/TextField';
|
import { TextFieldProps } from "@material-ui/core/TextField/TextField";
|
||||||
import { isXmrAddressValid } from 'utils/conversionUtils';
|
import { isXmrAddressValid } from "utils/conversionUtils";
|
||||||
import { isTestnet } from 'store/config';
|
import { isTestnet } from "store/config";
|
||||||
|
|
||||||
export default function MoneroAddressTextField({
|
export default function MoneroAddressTextField({
|
||||||
address,
|
address,
|
||||||
|
@ -16,10 +16,10 @@ export default function MoneroAddressTextField({
|
||||||
onAddressValidityChange: (valid: boolean) => void;
|
onAddressValidityChange: (valid: boolean) => void;
|
||||||
helperText: string;
|
helperText: string;
|
||||||
} & TextFieldProps) {
|
} & TextFieldProps) {
|
||||||
const placeholder = isTestnet() ? '59McWTPGc745...' : '888tNkZrPN6J...';
|
const placeholder = isTestnet() ? "59McWTPGc745..." : "888tNkZrPN6J...";
|
||||||
const errorText = isXmrAddressValid(address, isTestnet())
|
const errorText = isXmrAddressValid(address, isTestnet())
|
||||||
? null
|
? null
|
||||||
: 'Not a valid Monero address';
|
: "Not a valid Monero address";
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
onAddressValidityChange(!errorText);
|
onAddressValidityChange(!errorText);
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { DialogTitle, makeStyles, Typography } from '@material-ui/core';
|
import { DialogTitle, makeStyles, Typography } from "@material-ui/core";
|
||||||
|
|
||||||
const useStyles = makeStyles({
|
const useStyles = makeStyles({
|
||||||
root: {
|
root: {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
justifyContent: 'space-between',
|
justifyContent: "space-between",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { Button, makeStyles, Paper, Typography } from '@material-ui/core';
|
import { Button, makeStyles, Paper, Typography } from "@material-ui/core";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
logsOuter: {
|
logsOuter: {
|
||||||
overflow: 'auto',
|
overflow: "auto",
|
||||||
padding: theme.spacing(1),
|
padding: theme.spacing(1),
|
||||||
marginTop: theme.spacing(1),
|
marginTop: theme.spacing(1),
|
||||||
marginBottom: theme.spacing(1),
|
marginBottom: theme.spacing(1),
|
||||||
maxHeight: '10rem',
|
maxHeight: "10rem",
|
||||||
},
|
},
|
||||||
copyButton: {
|
copyButton: {
|
||||||
marginTop: theme.spacing(1),
|
marginTop: theme.spacing(1),
|
||||||
|
@ -17,7 +17,7 @@ export default function PaperTextBox({ stdOut }: { stdOut: string }) {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
function handleCopyLogs() {
|
function handleCopyLogs() {
|
||||||
throw new Error('Not implemented');
|
throw new Error("Not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -5,8 +5,8 @@ import {
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogContentText,
|
DialogContentText,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from '@material-ui/core';
|
} from "@material-ui/core";
|
||||||
import IpcInvokeButton from '../IpcInvokeButton';
|
import IpcInvokeButton from "../IpcInvokeButton";
|
||||||
|
|
||||||
type SwapCancelAlertProps = {
|
type SwapCancelAlertProps = {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
|
|
@ -69,8 +69,7 @@ function SwapSelectDropDown({
|
||||||
{swaps.map((swap) => (
|
{swaps.map((swap) => (
|
||||||
<MenuItem value={swap.swap_id}>
|
<MenuItem value={swap.swap_id}>
|
||||||
Swap {swap.swap_id.substring(0, 5)}... from{" "}
|
Swap {swap.swap_id.substring(0, 5)}... from{" "}
|
||||||
{new Date(parseDateString(swap.start_date)).toDateString()}{" "}
|
{new Date(parseDateString(swap.start_date)).toDateString()} (
|
||||||
(
|
|
||||||
<PiconeroAmount amount={swap.xmr_amount} />)
|
<PiconeroAmount amount={swap.xmr_amount} />)
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
|
@ -104,11 +103,11 @@ export default function FeedbackDialog({
|
||||||
<DialogTitle>Submit Feedback</DialogTitle>
|
<DialogTitle>Submit Feedback</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogContentText>
|
<DialogContentText>
|
||||||
Got something to say? Drop us a message below. If you had an
|
Got something to say? Drop us a message below. If you had an issue
|
||||||
issue with a specific swap, select it from the dropdown to
|
with a specific swap, select it from the dropdown to attach the logs.
|
||||||
attach the logs. It will help us figure out what went wrong.
|
It will help us figure out what went wrong. Hit that submit button
|
||||||
Hit that submit button when you are ready. We appreciate you
|
when you are ready. We appreciate you taking the time to share your
|
||||||
taking the time to share your thoughts!
|
thoughts!
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
|
@ -150,24 +149,15 @@ export default function FeedbackDialog({
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setPending(true);
|
setPending(true);
|
||||||
await submitFeedback(
|
await submitFeedback(bodyText, selectedAttachedSwap);
|
||||||
bodyText,
|
enqueueSnackbar("Feedback submitted successfully!", {
|
||||||
selectedAttachedSwap,
|
|
||||||
);
|
|
||||||
enqueueSnackbar(
|
|
||||||
"Feedback submitted successfully!",
|
|
||||||
{
|
|
||||||
variant: "success",
|
variant: "success",
|
||||||
},
|
});
|
||||||
);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(`Failed to submit feedback: ${e}`);
|
console.error(`Failed to submit feedback: ${e}`);
|
||||||
enqueueSnackbar(
|
enqueueSnackbar(`Failed to submit feedback (${e})`, {
|
||||||
`Failed to submit feedback (${e})`,
|
|
||||||
{
|
|
||||||
variant: "error",
|
variant: "error",
|
||||||
},
|
});
|
||||||
);
|
|
||||||
} finally {
|
} finally {
|
||||||
setPending(false);
|
setPending(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { ChangeEvent, useState } from 'react';
|
import { ChangeEvent, useState } from "react";
|
||||||
import {
|
import {
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
Dialog,
|
Dialog,
|
||||||
|
@ -11,20 +11,20 @@ import {
|
||||||
Chip,
|
Chip,
|
||||||
makeStyles,
|
makeStyles,
|
||||||
Theme,
|
Theme,
|
||||||
} from '@material-ui/core';
|
} from "@material-ui/core";
|
||||||
import { Multiaddr } from 'multiaddr';
|
import { Multiaddr } from "multiaddr";
|
||||||
import { useSnackbar } from 'notistack';
|
import { useSnackbar } from "notistack";
|
||||||
import IpcInvokeButton from '../../IpcInvokeButton';
|
import IpcInvokeButton from "../../IpcInvokeButton";
|
||||||
|
|
||||||
const PRESET_RENDEZVOUS_POINTS = [
|
const PRESET_RENDEZVOUS_POINTS = [
|
||||||
'/dns4/discover.unstoppableswap.net/tcp/8888/p2p/12D3KooWA6cnqJpVnreBVnoro8midDL9Lpzmg8oJPoAGi7YYaamE',
|
"/dns4/discover.unstoppableswap.net/tcp/8888/p2p/12D3KooWA6cnqJpVnreBVnoro8midDL9Lpzmg8oJPoAGi7YYaamE",
|
||||||
'/dns4/eratosthen.es/tcp/7798/p2p/12D3KooWAh7EXXa2ZyegzLGdjvj1W4G3EXrTGrf6trraoT1MEobs',
|
"/dns4/eratosthen.es/tcp/7798/p2p/12D3KooWAh7EXXa2ZyegzLGdjvj1W4G3EXrTGrf6trraoT1MEobs",
|
||||||
];
|
];
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) => ({
|
const useStyles = makeStyles((theme: Theme) => ({
|
||||||
chipOuter: {
|
chipOuter: {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexWrap: 'wrap',
|
flexWrap: "wrap",
|
||||||
gap: theme.spacing(1),
|
gap: theme.spacing(1),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
@ -39,7 +39,7 @@ export default function ListSellersDialog({
|
||||||
onClose,
|
onClose,
|
||||||
}: ListSellersDialogProps) {
|
}: ListSellersDialogProps) {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const [rendezvousAddress, setRendezvousAddress] = useState('');
|
const [rendezvousAddress, setRendezvousAddress] = useState("");
|
||||||
const { enqueueSnackbar } = useSnackbar();
|
const { enqueueSnackbar } = useSnackbar();
|
||||||
|
|
||||||
function handleMultiAddrChange(event: ChangeEvent<HTMLInputElement>) {
|
function handleMultiAddrChange(event: ChangeEvent<HTMLInputElement>) {
|
||||||
|
@ -49,12 +49,12 @@ export default function ListSellersDialog({
|
||||||
function getMultiAddressError(): string | null {
|
function getMultiAddressError(): string | null {
|
||||||
try {
|
try {
|
||||||
const multiAddress = new Multiaddr(rendezvousAddress);
|
const multiAddress = new Multiaddr(rendezvousAddress);
|
||||||
if (!multiAddress.protoNames().includes('p2p')) {
|
if (!multiAddress.protoNames().includes("p2p")) {
|
||||||
return 'The multi address must contain the peer id (/p2p/)';
|
return "The multi address must contain the peer id (/p2p/)";
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return 'Not a valid multi address';
|
return "Not a valid multi address";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ export default function ListSellersDialog({
|
||||||
}
|
}
|
||||||
|
|
||||||
enqueueSnackbar(message, {
|
enqueueSnackbar(message, {
|
||||||
variant: 'success',
|
variant: "success",
|
||||||
autoHideDuration: 5000,
|
autoHideDuration: 5000,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ export default function ListSellersDialog({
|
||||||
label="Rendezvous point"
|
label="Rendezvous point"
|
||||||
fullWidth
|
fullWidth
|
||||||
helperText={
|
helperText={
|
||||||
getMultiAddressError() || 'Multiaddress of the rendezvous point'
|
getMultiAddressError() || "Multiaddress of the rendezvous point"
|
||||||
}
|
}
|
||||||
value={rendezvousAddress}
|
value={rendezvousAddress}
|
||||||
onChange={handleMultiAddrChange}
|
onChange={handleMultiAddrChange}
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
import { makeStyles, Box, Typography, Chip, Tooltip } from '@material-ui/core';
|
import { makeStyles, Box, Typography, Chip, Tooltip } from "@material-ui/core";
|
||||||
import { VerifiedUser } from '@material-ui/icons';
|
import { VerifiedUser } from "@material-ui/icons";
|
||||||
import { satsToBtc, secondsToDays } from 'utils/conversionUtils';
|
import { satsToBtc, secondsToDays } from "utils/conversionUtils";
|
||||||
import { ExtendedProviderStatus } from 'models/apiModel';
|
import { ExtendedProviderStatus } from "models/apiModel";
|
||||||
import {
|
import {
|
||||||
MoneroBitcoinExchangeRate,
|
MoneroBitcoinExchangeRate,
|
||||||
SatsAmount,
|
SatsAmount,
|
||||||
} from 'renderer/components/other/Units';
|
} from "renderer/components/other/Units";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
content: {
|
content: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
'& *': {
|
"& *": {
|
||||||
lineBreak: 'anywhere',
|
lineBreak: "anywhere",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
chipsOuter: {
|
chipsOuter: {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
marginTop: theme.spacing(1),
|
marginTop: theme.spacing(1),
|
||||||
gap: theme.spacing(0.5),
|
gap: theme.spacing(0.5),
|
||||||
flexWrap: 'wrap',
|
flexWrap: "wrap",
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ export default function ProviderInfo({
|
||||||
{provider.peerId.substring(0, 8)}...{provider.peerId.slice(-8)}
|
{provider.peerId.substring(0, 8)}...{provider.peerId.slice(-8)}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="caption">
|
<Typography variant="caption">
|
||||||
Exchange rate:{' '}
|
Exchange rate:{" "}
|
||||||
<MoneroBitcoinExchangeRate rate={satsToBtc(provider.price)} />
|
<MoneroBitcoinExchangeRate rate={satsToBtc(provider.price)} />
|
||||||
<br />
|
<br />
|
||||||
Minimum swap amount: <SatsAmount amount={provider.minSwapAmount} />
|
Minimum swap amount: <SatsAmount amount={provider.minSwapAmount} />
|
||||||
|
@ -49,7 +49,7 @@ export default function ProviderInfo({
|
||||||
Maximum swap amount: <SatsAmount amount={provider.maxSwapAmount} />
|
Maximum swap amount: <SatsAmount amount={provider.maxSwapAmount} />
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box className={classes.chipsOuter}>
|
<Box className={classes.chipsOuter}>
|
||||||
<Chip label={provider.testnet ? 'Testnet' : 'Mainnet'} />
|
<Chip label={provider.testnet ? "Testnet" : "Mainnet"} />
|
||||||
{provider.uptime && (
|
{provider.uptime && (
|
||||||
<Tooltip title="A high uptime indicates reliability. Providers with low uptime may be unreliable and cause swaps to take longer to complete or fail entirely.">
|
<Tooltip title="A high uptime indicates reliability. Providers with low uptime may be unreliable and cause swaps to take longer to complete or fail entirely.">
|
||||||
<Chip label={`${Math.round(provider.uptime * 100)} % uptime`} />
|
<Chip label={`${Math.round(provider.uptime * 100)} % uptime`} />
|
||||||
|
@ -58,7 +58,7 @@ export default function ProviderInfo({
|
||||||
{provider.age ? (
|
{provider.age ? (
|
||||||
<Chip
|
<Chip
|
||||||
label={`Went online ${Math.round(secondsToDays(provider.age))} ${
|
label={`Went online ${Math.round(secondsToDays(provider.age))} ${
|
||||||
provider.age === 1 ? 'day' : 'days'
|
provider.age === 1 ? "day" : "days"
|
||||||
} ago`}
|
} ago`}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
@ -11,21 +11,21 @@ import {
|
||||||
DialogContent,
|
DialogContent,
|
||||||
makeStyles,
|
makeStyles,
|
||||||
CircularProgress,
|
CircularProgress,
|
||||||
} from '@material-ui/core';
|
} from "@material-ui/core";
|
||||||
import AddIcon from '@material-ui/icons/Add';
|
import AddIcon from "@material-ui/icons/Add";
|
||||||
import { useState } from 'react';
|
import { useState } from "react";
|
||||||
import SearchIcon from '@material-ui/icons/Search';
|
import SearchIcon from "@material-ui/icons/Search";
|
||||||
import { ExtendedProviderStatus } from 'models/apiModel';
|
import { ExtendedProviderStatus } from "models/apiModel";
|
||||||
import {
|
import {
|
||||||
useAllProviders,
|
useAllProviders,
|
||||||
useAppDispatch,
|
useAppDispatch,
|
||||||
useIsRpcEndpointBusy,
|
useIsRpcEndpointBusy,
|
||||||
} from 'store/hooks';
|
} from "store/hooks";
|
||||||
import { setSelectedProvider } from 'store/features/providersSlice';
|
import { setSelectedProvider } from "store/features/providersSlice";
|
||||||
import { RpcMethod } from 'models/rpcModel';
|
import { RpcMethod } from "models/rpcModel";
|
||||||
import ProviderSubmitDialog from './ProviderSubmitDialog';
|
import ProviderSubmitDialog from "./ProviderSubmitDialog";
|
||||||
import ListSellersDialog from '../listSellers/ListSellersDialog';
|
import ListSellersDialog from "../listSellers/ListSellersDialog";
|
||||||
import ProviderInfo from './ProviderInfo';
|
import ProviderInfo from "./ProviderInfo";
|
||||||
|
|
||||||
const useStyles = makeStyles({
|
const useStyles = makeStyles({
|
||||||
dialogContent: {
|
dialogContent: {
|
||||||
|
|
|
@ -4,25 +4,25 @@ import {
|
||||||
CardContent,
|
CardContent,
|
||||||
Box,
|
Box,
|
||||||
IconButton,
|
IconButton,
|
||||||
} from '@material-ui/core';
|
} from "@material-ui/core";
|
||||||
import ArrowForwardIosIcon from '@material-ui/icons/ArrowForwardIos';
|
import ArrowForwardIosIcon from "@material-ui/icons/ArrowForwardIos";
|
||||||
import { useState } from 'react';
|
import { useState } from "react";
|
||||||
import { useAppSelector } from 'store/hooks';
|
import { useAppSelector } from "store/hooks";
|
||||||
import ProviderInfo from './ProviderInfo';
|
import ProviderInfo from "./ProviderInfo";
|
||||||
import ProviderListDialog from './ProviderListDialog';
|
import ProviderListDialog from "./ProviderListDialog";
|
||||||
|
|
||||||
const useStyles = makeStyles({
|
const useStyles = makeStyles({
|
||||||
inner: {
|
inner: {
|
||||||
textAlign: 'left',
|
textAlign: "left",
|
||||||
width: '100%',
|
width: "100%",
|
||||||
height: '100%',
|
height: "100%",
|
||||||
},
|
},
|
||||||
providerCard: {
|
providerCard: {
|
||||||
width: '100%',
|
width: "100%",
|
||||||
},
|
},
|
||||||
providerCardContent: {
|
providerCardContent: {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { ChangeEvent, useState } from 'react';
|
import { ChangeEvent, useState } from "react";
|
||||||
import {
|
import {
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
Dialog,
|
Dialog,
|
||||||
|
@ -7,8 +7,8 @@ import {
|
||||||
TextField,
|
TextField,
|
||||||
DialogActions,
|
DialogActions,
|
||||||
Button,
|
Button,
|
||||||
} from '@material-ui/core';
|
} from "@material-ui/core";
|
||||||
import { Multiaddr } from 'multiaddr';
|
import { Multiaddr } from "multiaddr";
|
||||||
|
|
||||||
type ProviderSubmitDialogProps = {
|
type ProviderSubmitDialogProps = {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
@ -19,23 +19,23 @@ export default function ProviderSubmitDialog({
|
||||||
open,
|
open,
|
||||||
onClose,
|
onClose,
|
||||||
}: ProviderSubmitDialogProps) {
|
}: ProviderSubmitDialogProps) {
|
||||||
const [multiAddr, setMultiAddr] = useState('');
|
const [multiAddr, setMultiAddr] = useState("");
|
||||||
const [peerId, setPeerId] = useState('');
|
const [peerId, setPeerId] = useState("");
|
||||||
|
|
||||||
async function handleProviderSubmit() {
|
async function handleProviderSubmit() {
|
||||||
if (multiAddr && peerId) {
|
if (multiAddr && peerId) {
|
||||||
await fetch('https://api.unstoppableswap.net/api/submit-provider', {
|
await fetch("https://api.unstoppableswap.net/api/submit-provider", {
|
||||||
method: 'post',
|
method: "post",
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
multiAddr,
|
multiAddr,
|
||||||
peerId,
|
peerId,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
setMultiAddr('');
|
setMultiAddr("");
|
||||||
setPeerId('');
|
setPeerId("");
|
||||||
onClose();
|
onClose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,15 +51,15 @@ export default function ProviderSubmitDialog({
|
||||||
function getMultiAddressError(): string | null {
|
function getMultiAddressError(): string | null {
|
||||||
try {
|
try {
|
||||||
const multiAddress = new Multiaddr(multiAddr);
|
const multiAddress = new Multiaddr(multiAddr);
|
||||||
if (multiAddress.protoNames().includes('p2p')) {
|
if (multiAddress.protoNames().includes("p2p")) {
|
||||||
return 'The multi address should not contain the peer id (/p2p/)';
|
return "The multi address should not contain the peer id (/p2p/)";
|
||||||
}
|
}
|
||||||
if (multiAddress.protoNames().find((name) => name.includes('onion'))) {
|
if (multiAddress.protoNames().find((name) => name.includes("onion"))) {
|
||||||
return 'It is currently not possible to add a provider that is only reachable via Tor';
|
return "It is currently not possible to add a provider that is only reachable via Tor";
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return 'Not a valid multi address';
|
return "Not a valid multi address";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ export default function ProviderSubmitDialog({
|
||||||
fullWidth
|
fullWidth
|
||||||
helperText={
|
helperText={
|
||||||
getMultiAddressError() ||
|
getMultiAddressError() ||
|
||||||
'Tells the swap client where the provider can be reached'
|
"Tells the swap client where the provider can be reached"
|
||||||
}
|
}
|
||||||
value={multiAddr}
|
value={multiAddr}
|
||||||
onChange={handleMultiAddrChange}
|
onChange={handleMultiAddrChange}
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import QRCode from 'react-qr-code';
|
import QRCode from "react-qr-code";
|
||||||
import { Box } from '@material-ui/core';
|
import { Box } from "@material-ui/core";
|
||||||
|
|
||||||
export default function BitcoinQrCode({ address }: { address: string }) {
|
export default function BitcoinQrCode({ address }: { address: string }) {
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
height: '100%',
|
height: "100%",
|
||||||
margin: '0 auto',
|
margin: "0 auto",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<QRCode
|
<QRCode
|
||||||
value={`bitcoin:${address}`}
|
value={`bitcoin:${address}`}
|
||||||
size={256}
|
size={256}
|
||||||
style={{ height: 'auto', maxWidth: '100%', width: '100%' }}
|
style={{ height: "auto", maxWidth: "100%", width: "100%" }}
|
||||||
/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */
|
/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */
|
||||||
/* @ts-ignore */
|
/* @ts-ignore */
|
||||||
viewBox="0 0 256 256"
|
viewBox="0 0 256 256"
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { isTestnet } from 'store/config';
|
import { isTestnet } from "store/config";
|
||||||
import { getBitcoinTxExplorerUrl } from 'utils/conversionUtils';
|
import { getBitcoinTxExplorerUrl } from "utils/conversionUtils";
|
||||||
import BitcoinIcon from 'renderer/components/icons/BitcoinIcon';
|
import BitcoinIcon from "renderer/components/icons/BitcoinIcon";
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from "react";
|
||||||
import TransactionInfoBox from './TransactionInfoBox';
|
import TransactionInfoBox from "./TransactionInfoBox";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
title: string;
|
title: string;
|
||||||
|
|
|
@ -3,8 +3,8 @@ import {
|
||||||
CircularProgress,
|
CircularProgress,
|
||||||
makeStyles,
|
makeStyles,
|
||||||
Typography,
|
Typography,
|
||||||
} from '@material-ui/core';
|
} from "@material-ui/core";
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from "react";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
subtitle: {
|
subtitle: {
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { Button } from '@material-ui/core';
|
import { Button } from "@material-ui/core";
|
||||||
import { ButtonProps } from '@material-ui/core/Button/Button';
|
import { ButtonProps } from "@material-ui/core/Button/Button";
|
||||||
|
|
||||||
export default function ClipboardIconButton({
|
export default function ClipboardIconButton({
|
||||||
text,
|
text,
|
||||||
...props
|
...props
|
||||||
}: { text: string } & ButtonProps) {
|
}: { text: string } & ButtonProps) {
|
||||||
function writeToClipboard() {
|
function writeToClipboard() {
|
||||||
throw new Error('Not implemented');
|
throw new Error("Not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from "react";
|
||||||
import { Box, Typography } from '@material-ui/core';
|
import { Box, Typography } from "@material-ui/core";
|
||||||
import FileCopyOutlinedIcon from '@material-ui/icons/FileCopyOutlined';
|
import FileCopyOutlinedIcon from "@material-ui/icons/FileCopyOutlined";
|
||||||
import InfoBox from './InfoBox';
|
import InfoBox from "./InfoBox";
|
||||||
import ClipboardIconButton from './ClipbiardIconButton';
|
import ClipboardIconButton from "./ClipbiardIconButton";
|
||||||
import BitcoinQrCode from './BitcoinQrCode';
|
import BitcoinQrCode from "./BitcoinQrCode";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
title: string;
|
title: string;
|
||||||
|
@ -34,10 +34,10 @@ export default function DepositAddressInfoBox({
|
||||||
/>
|
/>
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'row',
|
flexDirection: "row",
|
||||||
gap: '0.5rem',
|
gap: "0.5rem",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box>{additionalContent}</Box>
|
<Box>{additionalContent}</Box>
|
||||||
|
|
|
@ -4,8 +4,8 @@ import {
|
||||||
makeStyles,
|
makeStyles,
|
||||||
Paper,
|
Paper,
|
||||||
Typography,
|
Typography,
|
||||||
} from '@material-ui/core';
|
} from "@material-ui/core";
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from "react";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
title: ReactNode;
|
title: ReactNode;
|
||||||
|
@ -18,14 +18,14 @@ type Props = {
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
outer: {
|
outer: {
|
||||||
padding: theme.spacing(1.5),
|
padding: theme.spacing(1.5),
|
||||||
overflow: 'hidden',
|
overflow: "hidden",
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
gap: theme.spacing(1),
|
gap: theme.spacing(1),
|
||||||
},
|
},
|
||||||
upperContent: {
|
upperContent: {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
gap: theme.spacing(0.5),
|
gap: theme.spacing(0.5),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { isTestnet } from 'store/config';
|
import { isTestnet } from "store/config";
|
||||||
import { getMoneroTxExplorerUrl } from 'utils/conversionUtils';
|
import { getMoneroTxExplorerUrl } from "utils/conversionUtils";
|
||||||
import MoneroIcon from 'renderer/components/icons/MoneroIcon';
|
import MoneroIcon from "renderer/components/icons/MoneroIcon";
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from "react";
|
||||||
import TransactionInfoBox from './TransactionInfoBox';
|
import TransactionInfoBox from "./TransactionInfoBox";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
title: string;
|
title: string;
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
import { useState } from 'react';
|
import { useState } from "react";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogActions,
|
DialogActions,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
makeStyles,
|
makeStyles,
|
||||||
} from '@material-ui/core';
|
} from "@material-ui/core";
|
||||||
import { useAppDispatch, useAppSelector } from 'store/hooks';
|
import { useAppDispatch, useAppSelector } from "store/hooks";
|
||||||
import { swapReset } from 'store/features/swapSlice';
|
import { swapReset } from "store/features/swapSlice";
|
||||||
import SwapStatePage from './pages/SwapStatePage';
|
import SwapStatePage from "./pages/SwapStatePage";
|
||||||
import SwapStateStepper from './SwapStateStepper';
|
import SwapStateStepper from "./SwapStateStepper";
|
||||||
import SwapSuspendAlert from '../SwapSuspendAlert';
|
import SwapSuspendAlert from "../SwapSuspendAlert";
|
||||||
import SwapDialogTitle from './SwapDialogTitle';
|
import SwapDialogTitle from "./SwapDialogTitle";
|
||||||
import DebugPage from './pages/DebugPage';
|
import DebugPage from "./pages/DebugPage";
|
||||||
|
|
||||||
const useStyles = makeStyles({
|
const useStyles = makeStyles({
|
||||||
content: {
|
content: {
|
||||||
minHeight: '25rem',
|
minHeight: "25rem",
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
justifyContent: 'space-between',
|
justifyContent: "space-between",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,17 @@
|
||||||
import {
|
import { Box, DialogTitle, makeStyles, Typography } from "@material-ui/core";
|
||||||
Box,
|
import TorStatusBadge from "./pages/TorStatusBadge";
|
||||||
DialogTitle,
|
import FeedbackSubmitBadge from "./pages/FeedbackSubmitBadge";
|
||||||
makeStyles,
|
import DebugPageSwitchBadge from "./pages/DebugPageSwitchBadge";
|
||||||
Typography,
|
|
||||||
} from '@material-ui/core';
|
|
||||||
import TorStatusBadge from './pages/TorStatusBadge';
|
|
||||||
import FeedbackSubmitBadge from './pages/FeedbackSubmitBadge';
|
|
||||||
import DebugPageSwitchBadge from './pages/DebugPageSwitchBadge';
|
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
root: {
|
root: {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
justifyContent: 'space-between',
|
justifyContent: "space-between",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
},
|
},
|
||||||
rightSide: {
|
rightSide: {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
gridGap: theme.spacing(1),
|
gridGap: theme.spacing(1),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -152,10 +152,7 @@ export default function SwapStateStepper() {
|
||||||
const currentSwapSpawnType = useAppSelector((s) => s.swap.spawnType);
|
const currentSwapSpawnType = useAppSelector((s) => s.swap.spawnType);
|
||||||
const stateName = useActiveSwapInfo()?.state_name ?? null;
|
const stateName = useActiveSwapInfo()?.state_name ?? null;
|
||||||
const processExited = useAppSelector((s) => !s.swap.processRunning);
|
const processExited = useAppSelector((s) => !s.swap.processRunning);
|
||||||
const [pathType, activeStep, error] = getActiveStep(
|
const [pathType, activeStep, error] = getActiveStep(stateName, processExited);
|
||||||
stateName,
|
|
||||||
processExited,
|
|
||||||
);
|
|
||||||
|
|
||||||
// If the current swap is being manually cancelled and refund, we want to show the unhappy path even though the current state is not a "unhappy" state
|
// If the current swap is being manually cancelled and refund, we want to show the unhappy path even though the current state is not a "unhappy" state
|
||||||
if (currentSwapSpawnType === SwapSpawnType.CANCEL_REFUND) {
|
if (currentSwapSpawnType === SwapSpawnType.CANCEL_REFUND) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Link, Typography } from '@material-ui/core';
|
import { Link, Typography } from "@material-ui/core";
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from "react";
|
||||||
import InfoBox from './InfoBox';
|
import InfoBox from "./InfoBox";
|
||||||
|
|
||||||
type TransactionInfoBoxProps = {
|
type TransactionInfoBoxProps = {
|
||||||
title: string;
|
title: string;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Tooltip } from '@material-ui/core';
|
import { Tooltip } from "@material-ui/core";
|
||||||
import IconButton from '@material-ui/core/IconButton';
|
import IconButton from "@material-ui/core/IconButton";
|
||||||
import DeveloperBoardIcon from '@material-ui/icons/DeveloperBoard';
|
import DeveloperBoardIcon from "@material-ui/icons/DeveloperBoard";
|
||||||
|
|
||||||
export default function DebugPageSwitchBadge({
|
export default function DebugPageSwitchBadge({
|
||||||
enabled,
|
enabled,
|
||||||
|
@ -14,10 +14,10 @@ export default function DebugPageSwitchBadge({
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip title={enabled ? 'Hide debug view' : 'Show debug view'}>
|
<Tooltip title={enabled ? "Hide debug view" : "Show debug view"}>
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={handleToggle}
|
onClick={handleToggle}
|
||||||
color={enabled ? 'primary' : 'default'}
|
color={enabled ? "primary" : "default"}
|
||||||
>
|
>
|
||||||
<DeveloperBoardIcon />
|
<DeveloperBoardIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { IconButton } from '@material-ui/core';
|
import { IconButton } from "@material-ui/core";
|
||||||
import FeedbackIcon from '@material-ui/icons/Feedback';
|
import FeedbackIcon from "@material-ui/icons/Feedback";
|
||||||
import FeedbackDialog from '../../feedback/FeedbackDialog';
|
import FeedbackDialog from "../../feedback/FeedbackDialog";
|
||||||
import { useState } from 'react';
|
import { useState } from "react";
|
||||||
|
|
||||||
export default function FeedbackSubmitBadge() {
|
export default function FeedbackSubmitBadge() {
|
||||||
const [showFeedbackDialog, setShowFeedbackDialog] = useState(false);
|
const [showFeedbackDialog, setShowFeedbackDialog] = useState(false);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Box } from '@material-ui/core';
|
import { Box } from "@material-ui/core";
|
||||||
import { useAppSelector } from 'store/hooks';
|
import { useAppSelector } from "store/hooks";
|
||||||
import {
|
import {
|
||||||
isSwapStateBtcCancelled,
|
isSwapStateBtcCancelled,
|
||||||
isSwapStateBtcLockInMempool,
|
isSwapStateBtcLockInMempool,
|
||||||
|
@ -15,23 +15,23 @@ import {
|
||||||
isSwapStateXmrLockInMempool,
|
isSwapStateXmrLockInMempool,
|
||||||
isSwapStateXmrRedeemInMempool,
|
isSwapStateXmrRedeemInMempool,
|
||||||
SwapState,
|
SwapState,
|
||||||
} from '../../../../../models/storeModel';
|
} from "../../../../../models/storeModel";
|
||||||
import InitiatedPage from './init/InitiatedPage';
|
import InitiatedPage from "./init/InitiatedPage";
|
||||||
import WaitingForBitcoinDepositPage from './init/WaitingForBitcoinDepositPage';
|
import WaitingForBitcoinDepositPage from "./init/WaitingForBitcoinDepositPage";
|
||||||
import StartedPage from './in_progress/StartedPage';
|
import StartedPage from "./in_progress/StartedPage";
|
||||||
import BitcoinLockTxInMempoolPage from './in_progress/BitcoinLockTxInMempoolPage';
|
import BitcoinLockTxInMempoolPage from "./in_progress/BitcoinLockTxInMempoolPage";
|
||||||
import XmrLockTxInMempoolPage from './in_progress/XmrLockInMempoolPage';
|
import XmrLockTxInMempoolPage from "./in_progress/XmrLockInMempoolPage";
|
||||||
// eslint-disable-next-line import/no-cycle
|
// eslint-disable-next-line import/no-cycle
|
||||||
import ProcessExitedPage from './exited/ProcessExitedPage';
|
import ProcessExitedPage from "./exited/ProcessExitedPage";
|
||||||
import XmrRedeemInMempoolPage from './done/XmrRedeemInMempoolPage';
|
import XmrRedeemInMempoolPage from "./done/XmrRedeemInMempoolPage";
|
||||||
import ReceivedQuotePage from './in_progress/ReceivedQuotePage';
|
import ReceivedQuotePage from "./in_progress/ReceivedQuotePage";
|
||||||
import BitcoinRedeemedPage from './in_progress/BitcoinRedeemedPage';
|
import BitcoinRedeemedPage from "./in_progress/BitcoinRedeemedPage";
|
||||||
import InitPage from './init/InitPage';
|
import InitPage from "./init/InitPage";
|
||||||
import XmrLockedPage from './in_progress/XmrLockedPage';
|
import XmrLockedPage from "./in_progress/XmrLockedPage";
|
||||||
import BitcoinCancelledPage from './in_progress/BitcoinCancelledPage';
|
import BitcoinCancelledPage from "./in_progress/BitcoinCancelledPage";
|
||||||
import BitcoinRefundedPage from './done/BitcoinRefundedPage';
|
import BitcoinRefundedPage from "./done/BitcoinRefundedPage";
|
||||||
import BitcoinPunishedPage from './done/BitcoinPunishedPage';
|
import BitcoinPunishedPage from "./done/BitcoinPunishedPage";
|
||||||
import { SyncingMoneroWalletPage } from './in_progress/SyncingMoneroWalletPage';
|
import { SyncingMoneroWalletPage } from "./in_progress/SyncingMoneroWalletPage";
|
||||||
|
|
||||||
export default function SwapStatePage({
|
export default function SwapStatePage({
|
||||||
swapState,
|
swapState,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { IconButton, Tooltip } from '@material-ui/core';
|
import { IconButton, Tooltip } from "@material-ui/core";
|
||||||
import { useAppSelector } from 'store/hooks';
|
import { useAppSelector } from "store/hooks";
|
||||||
import TorIcon from '../../../icons/TorIcon';
|
import TorIcon from "../../../icons/TorIcon";
|
||||||
|
|
||||||
export default function TorStatusBadge() {
|
export default function TorStatusBadge() {
|
||||||
const tor = useAppSelector((s) => s.tor);
|
const tor = useAppSelector((s) => s.tor);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Box, DialogContentText } from '@material-ui/core';
|
import { Box, DialogContentText } from "@material-ui/core";
|
||||||
import FeedbackInfoBox from '../../../../pages/help/FeedbackInfoBox';
|
import FeedbackInfoBox from "../../../../pages/help/FeedbackInfoBox";
|
||||||
|
|
||||||
export default function BitcoinPunishedPage() {
|
export default function BitcoinPunishedPage() {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -17,10 +17,9 @@ export default function BitcoinRefundedPage({
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<DialogContentText>
|
<DialogContentText>
|
||||||
Unfortunately, the swap was not successful. However, rest
|
Unfortunately, the swap was not successful. However, rest assured that
|
||||||
assured that all your Bitcoin has been refunded to the specified
|
all your Bitcoin has been refunded to the specified address. The swap
|
||||||
address. The swap process is now complete, and you are free to
|
process is now complete, and you are free to exit the application.
|
||||||
exit the application.
|
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { Box, DialogContentText } from '@material-ui/core';
|
import { Box, DialogContentText } from "@material-ui/core";
|
||||||
import { SwapStateXmrRedeemInMempool } from 'models/storeModel';
|
import { SwapStateXmrRedeemInMempool } from "models/storeModel";
|
||||||
import { useActiveSwapInfo } from 'store/hooks';
|
import { useActiveSwapInfo } from "store/hooks";
|
||||||
import { getSwapXmrAmount } from 'models/rpcModel';
|
import { getSwapXmrAmount } from "models/rpcModel";
|
||||||
import MoneroTransactionInfoBox from '../../MoneroTransactionInfoBox';
|
import MoneroTransactionInfoBox from "../../MoneroTransactionInfoBox";
|
||||||
import FeedbackInfoBox from '../../../../pages/help/FeedbackInfoBox';
|
import FeedbackInfoBox from "../../../../pages/help/FeedbackInfoBox";
|
||||||
|
|
||||||
type XmrRedeemInMempoolPageProps = {
|
type XmrRedeemInMempoolPageProps = {
|
||||||
state: SwapStateXmrRedeemInMempool | null;
|
state: SwapStateXmrRedeemInMempool | null;
|
||||||
|
@ -27,9 +27,9 @@ export default function XmrRedeemInMempoolPage({
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
gap: '0.5rem',
|
gap: "0.5rem",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{state && (
|
{state && (
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import CircularProgressWithSubtitle from '../../CircularProgressWithSubtitle';
|
import CircularProgressWithSubtitle from "../../CircularProgressWithSubtitle";
|
||||||
|
|
||||||
export default function BitcoinCancelledPage() {
|
export default function BitcoinCancelledPage() {
|
||||||
return <CircularProgressWithSubtitle description="Refunding your Bitcoin" />;
|
return <CircularProgressWithSubtitle description="Refunding your Bitcoin" />;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Box, DialogContentText } from '@material-ui/core';
|
import { Box, DialogContentText } from "@material-ui/core";
|
||||||
import { SwapStateBtcLockInMempool } from 'models/storeModel';
|
import { SwapStateBtcLockInMempool } from "models/storeModel";
|
||||||
import BitcoinTransactionInfoBox from '../../BitcoinTransactionInfoBox';
|
import BitcoinTransactionInfoBox from "../../BitcoinTransactionInfoBox";
|
||||||
import SwapMightBeCancelledAlert from '../../../../alert/SwapMightBeCancelledAlert';
|
import SwapMightBeCancelledAlert from "../../../../alert/SwapMightBeCancelledAlert";
|
||||||
|
|
||||||
type BitcoinLockTxInMempoolPageProps = {
|
type BitcoinLockTxInMempoolPageProps = {
|
||||||
state: SwapStateBtcLockInMempool;
|
state: SwapStateBtcLockInMempool;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import CircularProgressWithSubtitle from '../../CircularProgressWithSubtitle';
|
import CircularProgressWithSubtitle from "../../CircularProgressWithSubtitle";
|
||||||
|
|
||||||
export default function BitcoinRedeemedPage() {
|
export default function BitcoinRedeemedPage() {
|
||||||
return <CircularProgressWithSubtitle description="Redeeming your Monero" />;
|
return <CircularProgressWithSubtitle description="Redeeming your Monero" />;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import CircularProgressWithSubtitle from '../../CircularProgressWithSubtitle';
|
import CircularProgressWithSubtitle from "../../CircularProgressWithSubtitle";
|
||||||
|
|
||||||
export default function ReceivedQuotePage() {
|
export default function ReceivedQuotePage() {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { SwapStateStarted } from 'models/storeModel';
|
import { SwapStateStarted } from "models/storeModel";
|
||||||
import { BitcoinAmount } from 'renderer/components/other/Units';
|
import { BitcoinAmount } from "renderer/components/other/Units";
|
||||||
import CircularProgressWithSubtitle from '../../CircularProgressWithSubtitle';
|
import CircularProgressWithSubtitle from "../../CircularProgressWithSubtitle";
|
||||||
|
|
||||||
export default function StartedPage({ state }: { state: SwapStateStarted }) {
|
export default function StartedPage({ state }: { state: SwapStateStarted }) {
|
||||||
const description = state.txLockDetails ? (
|
const description = state.txLockDetails ? (
|
||||||
|
@ -9,7 +9,7 @@ export default function StartedPage({ state }: { state: SwapStateStarted }) {
|
||||||
network fee of <BitcoinAmount amount={state.txLockDetails.fees} />
|
network fee of <BitcoinAmount amount={state.txLockDetails.fees} />
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
'Locking Bitcoin'
|
"Locking Bitcoin"
|
||||||
);
|
);
|
||||||
|
|
||||||
return <CircularProgressWithSubtitle description={description} />;
|
return <CircularProgressWithSubtitle description={description} />;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import CircularProgressWithSubtitle from '../../CircularProgressWithSubtitle';
|
import CircularProgressWithSubtitle from "../../CircularProgressWithSubtitle";
|
||||||
|
|
||||||
export function SyncingMoneroWalletPage() {
|
export function SyncingMoneroWalletPage() {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Box, DialogContentText } from '@material-ui/core';
|
import { Box, DialogContentText } from "@material-ui/core";
|
||||||
import { SwapStateXmrLockInMempool } from 'models/storeModel';
|
import { SwapStateXmrLockInMempool } from "models/storeModel";
|
||||||
import MoneroTransactionInfoBox from '../../MoneroTransactionInfoBox';
|
import MoneroTransactionInfoBox from "../../MoneroTransactionInfoBox";
|
||||||
|
|
||||||
type XmrLockTxInMempoolPageProps = {
|
type XmrLockTxInMempoolPageProps = {
|
||||||
state: SwapStateXmrLockInMempool;
|
state: SwapStateXmrLockInMempool;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import CircularProgressWithSubtitle from '../../CircularProgressWithSubtitle';
|
import CircularProgressWithSubtitle from "../../CircularProgressWithSubtitle";
|
||||||
|
|
||||||
export default function XmrLockedPage() {
|
export default function XmrLockedPage() {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
import { useState } from 'react';
|
import { useState } from "react";
|
||||||
import { Box, makeStyles, TextField, Typography } from '@material-ui/core';
|
import { Box, makeStyles, TextField, Typography } from "@material-ui/core";
|
||||||
import { SwapStateWaitingForBtcDeposit } from 'models/storeModel';
|
import { SwapStateWaitingForBtcDeposit } from "models/storeModel";
|
||||||
import { useAppSelector } from 'store/hooks';
|
import { useAppSelector } from "store/hooks";
|
||||||
import { satsToBtc } from 'utils/conversionUtils';
|
import { satsToBtc } from "utils/conversionUtils";
|
||||||
import { MoneroAmount } from '../../../../other/Units';
|
import { MoneroAmount } from "../../../../other/Units";
|
||||||
|
|
||||||
const MONERO_FEE = 0.000016;
|
const MONERO_FEE = 0.000016;
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
outer: {
|
outer: {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
gap: theme.spacing(1),
|
gap: theme.spacing(1),
|
||||||
},
|
},
|
||||||
textField: {
|
textField: {
|
||||||
'& input::-webkit-outer-spin-button, & input::-webkit-inner-spin-button': {
|
"& input::-webkit-outer-spin-button, & input::-webkit-inner-spin-button": {
|
||||||
display: 'none',
|
display: "none",
|
||||||
},
|
},
|
||||||
'& input[type=number]': {
|
"& input[type=number]": {
|
||||||
MozAppearance: 'textfield',
|
MozAppearance: "textfield",
|
||||||
},
|
},
|
||||||
maxWidth: theme.spacing(16),
|
maxWidth: theme.spacing(16),
|
||||||
},
|
},
|
||||||
|
@ -83,7 +83,7 @@ export default function DepositAmountHelper({
|
||||||
className={classes.textField}
|
className={classes.textField}
|
||||||
/>
|
/>
|
||||||
<Typography variant="subtitle2">
|
<Typography variant="subtitle2">
|
||||||
BTC will give you approximately{' '}
|
BTC will give you approximately{" "}
|
||||||
<MoneroAmount amount={calcXMRAmount()} />.
|
<MoneroAmount amount={calcXMRAmount()} />.
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import CircularProgressWithSubtitle from '../../CircularProgressWithSubtitle';
|
import CircularProgressWithSubtitle from "../../CircularProgressWithSubtitle";
|
||||||
import { MoneroWalletRpcUpdateState } from '../../../../../../models/storeModel';
|
import { MoneroWalletRpcUpdateState } from "../../../../../../models/storeModel";
|
||||||
|
|
||||||
export default function DownloadingMoneroWalletRpcPage({
|
export default function DownloadingMoneroWalletRpcPage({
|
||||||
updateState,
|
updateState,
|
||||||
|
|
|
@ -1,32 +1,28 @@
|
||||||
import { Box, DialogContentText, makeStyles } from '@material-ui/core';
|
import { Box, DialogContentText, makeStyles } from "@material-ui/core";
|
||||||
import { useState } from 'react';
|
import { useState } from "react";
|
||||||
import BitcoinAddressTextField from 'renderer/components/inputs/BitcoinAddressTextField';
|
import BitcoinAddressTextField from "renderer/components/inputs/BitcoinAddressTextField";
|
||||||
import MoneroAddressTextField from 'renderer/components/inputs/MoneroAddressTextField';
|
import MoneroAddressTextField from "renderer/components/inputs/MoneroAddressTextField";
|
||||||
import { useAppSelector } from 'store/hooks';
|
import { useAppSelector } from "store/hooks";
|
||||||
import PlayArrowIcon from '@material-ui/icons/PlayArrow';
|
import PlayArrowIcon from "@material-ui/icons/PlayArrow";
|
||||||
import { isTestnet } from 'store/config';
|
import { isTestnet } from "store/config";
|
||||||
import RemainingFundsWillBeUsedAlert from '../../../../alert/RemainingFundsWillBeUsedAlert';
|
import RemainingFundsWillBeUsedAlert from "../../../../alert/RemainingFundsWillBeUsedAlert";
|
||||||
import IpcInvokeButton from '../../../../IpcInvokeButton';
|
import IpcInvokeButton from "../../../../IpcInvokeButton";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
initButton: {
|
initButton: {
|
||||||
marginTop: theme.spacing(1),
|
marginTop: theme.spacing(1),
|
||||||
},
|
},
|
||||||
fieldsOuter: {
|
fieldsOuter: {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
gap: theme.spacing(2),
|
gap: theme.spacing(2),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export default function InitPage() {
|
export default function InitPage() {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const [redeemAddress, setRedeemAddress] = useState(
|
const [redeemAddress, setRedeemAddress] = useState("");
|
||||||
''
|
const [refundAddress, setRefundAddress] = useState("");
|
||||||
);
|
|
||||||
const [refundAddress, setRefundAddress] = useState(
|
|
||||||
''
|
|
||||||
);
|
|
||||||
const [redeemAddressValid, setRedeemAddressValid] = useState(false);
|
const [redeemAddressValid, setRedeemAddressValid] = useState(false);
|
||||||
const [refundAddressValid, setRefundAddressValid] = useState(false);
|
const [refundAddressValid, setRefundAddressValid] = useState(false);
|
||||||
const selectedProvider = useAppSelector(
|
const selectedProvider = useAppSelector(
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
import { useAppSelector } from 'store/hooks';
|
import { useAppSelector } from "store/hooks";
|
||||||
import { SwapSpawnType } from 'models/cliModel';
|
import { SwapSpawnType } from "models/cliModel";
|
||||||
import CircularProgressWithSubtitle from '../../CircularProgressWithSubtitle';
|
import CircularProgressWithSubtitle from "../../CircularProgressWithSubtitle";
|
||||||
|
|
||||||
export default function InitiatedPage() {
|
export default function InitiatedPage() {
|
||||||
const description = useAppSelector((s) => {
|
const description = useAppSelector((s) => {
|
||||||
switch (s.swap.spawnType) {
|
switch (s.swap.spawnType) {
|
||||||
case SwapSpawnType.INIT:
|
case SwapSpawnType.INIT:
|
||||||
return 'Requesting quote from provider...';
|
return "Requesting quote from provider...";
|
||||||
case SwapSpawnType.RESUME:
|
case SwapSpawnType.RESUME:
|
||||||
return 'Resuming swap...';
|
return "Resuming swap...";
|
||||||
case SwapSpawnType.CANCEL_REFUND:
|
case SwapSpawnType.CANCEL_REFUND:
|
||||||
return 'Attempting to cancel & refund swap...';
|
return "Attempting to cancel & refund swap...";
|
||||||
default:
|
default:
|
||||||
// Should never be hit
|
// Should never be hit
|
||||||
return 'Initiating swap...';
|
return "Initiating swap...";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
import { Box, makeStyles, Typography } from '@material-ui/core';
|
import { Box, makeStyles, Typography } from "@material-ui/core";
|
||||||
import { SwapStateWaitingForBtcDeposit } from 'models/storeModel';
|
import { SwapStateWaitingForBtcDeposit } from "models/storeModel";
|
||||||
import { useAppSelector } from 'store/hooks';
|
import { useAppSelector } from "store/hooks";
|
||||||
import DepositAddressInfoBox from '../../DepositAddressInfoBox';
|
import DepositAddressInfoBox from "../../DepositAddressInfoBox";
|
||||||
import BitcoinIcon from '../../../../icons/BitcoinIcon';
|
import BitcoinIcon from "../../../../icons/BitcoinIcon";
|
||||||
import DepositAmountHelper from './DepositAmountHelper';
|
import DepositAmountHelper from "./DepositAmountHelper";
|
||||||
import {
|
import {
|
||||||
BitcoinAmount,
|
BitcoinAmount,
|
||||||
MoneroBitcoinExchangeRate,
|
MoneroBitcoinExchangeRate,
|
||||||
SatsAmount,
|
SatsAmount,
|
||||||
} from '../../../../other/Units';
|
} from "../../../../other/Units";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
amountHelper: {
|
amountHelper: {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
},
|
},
|
||||||
additionalContent: {
|
additionalContent: {
|
||||||
paddingTop: theme.spacing(1),
|
paddingTop: theme.spacing(1),
|
||||||
gap: theme.spacing(0.5),
|
gap: theme.spacing(0.5),
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -45,13 +45,13 @@ export default function WaitingForBtcDepositPage({
|
||||||
<ul>
|
<ul>
|
||||||
{bitcoinBalance > 0 ? (
|
{bitcoinBalance > 0 ? (
|
||||||
<li>
|
<li>
|
||||||
You have already deposited{' '}
|
You have already deposited{" "}
|
||||||
<SatsAmount amount={bitcoinBalance} />
|
<SatsAmount amount={bitcoinBalance} />
|
||||||
</li>
|
</li>
|
||||||
) : null}
|
) : null}
|
||||||
<li>
|
<li>
|
||||||
Send any amount between{' '}
|
Send any amount between{" "}
|
||||||
<BitcoinAmount amount={state.minDeposit} /> and{' '}
|
<BitcoinAmount amount={state.minDeposit} /> and{" "}
|
||||||
<BitcoinAmount amount={state.maxDeposit} /> to the address
|
<BitcoinAmount amount={state.maxDeposit} /> to the address
|
||||||
above
|
above
|
||||||
{bitcoinBalance > 0 && (
|
{bitcoinBalance > 0 && (
|
||||||
|
@ -60,11 +60,11 @@ export default function WaitingForBtcDepositPage({
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
All Bitcoin sent to this this address will converted into
|
All Bitcoin sent to this this address will converted into
|
||||||
Monero at an exchance rate of{' '}
|
Monero at an exchance rate of{" "}
|
||||||
<MoneroBitcoinExchangeRate rate={state.price} />
|
<MoneroBitcoinExchangeRate rate={state.price} />
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
The network fee of{' '}
|
The network fee of{" "}
|
||||||
<BitcoinAmount amount={state.minBitcoinLockTxFee} /> will
|
<BitcoinAmount amount={state.minBitcoinLockTxFee} /> will
|
||||||
automatically be deducted from the deposited coins
|
automatically be deducted from the deposited coins
|
||||||
</li>
|
</li>
|
||||||
|
@ -74,9 +74,7 @@ export default function WaitingForBtcDepositPage({
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</Typography>
|
</Typography>
|
||||||
<DepositAmountHelper
|
<DepositAmountHelper state={state} />
|
||||||
state={state}
|
|
||||||
/>
|
|
||||||
</Box>
|
</Box>
|
||||||
}
|
}
|
||||||
icon={<BitcoinIcon />}
|
icon={<BitcoinIcon />}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { useState } from "react";
|
||||||
import { withdrawBtc } from "renderer/rpc";
|
import { withdrawBtc } from "renderer/rpc";
|
||||||
import BtcTxInMempoolPageContent from "./pages/BitcoinWithdrawTxInMempoolPage";
|
import BtcTxInMempoolPageContent from "./pages/BitcoinWithdrawTxInMempoolPage";
|
||||||
import AddressInputPage from "./pages/AddressInputPage";
|
import AddressInputPage from "./pages/AddressInputPage";
|
||||||
|
import WithdrawDialogContent from "./WithdrawDialogContent";
|
||||||
|
|
||||||
export default function WithdrawDialog({
|
export default function WithdrawDialog({
|
||||||
open,
|
open,
|
||||||
|
@ -30,12 +31,10 @@ export default function WithdrawDialog({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This prevents an issue where the Dialog is shown for a split second without a present withdraw state
|
|
||||||
if (!open) return null;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open onClose={onCancel} maxWidth="sm" fullWidth>
|
<Dialog open={open} onClose={onCancel} maxWidth="sm" fullWidth>
|
||||||
<DialogHeader title="Withdraw Bitcoin" />
|
<DialogHeader title="Withdraw Bitcoin" />
|
||||||
|
<WithdrawDialogContent isPending={pending} withdrawTxId={withdrawTxId}>
|
||||||
{withdrawTxId === null ? (
|
{withdrawTxId === null ? (
|
||||||
<AddressInputPage
|
<AddressInputPage
|
||||||
setWithdrawAddress={setWithdrawAddress}
|
setWithdrawAddress={setWithdrawAddress}
|
||||||
|
@ -48,9 +47,14 @@ export default function WithdrawDialog({
|
||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
</WithdrawDialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
{withdrawTxId === null ? (
|
<Button onClick={onCancel} color="primary" disabled={pending}>
|
||||||
|
{withdrawTxId === null ? "Cancel" : "Done"}
|
||||||
|
</Button>
|
||||||
|
{withdrawTxId === null && (
|
||||||
<PromiseInvokeButton
|
<PromiseInvokeButton
|
||||||
|
displayErrorSnackbar
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
disabled={!withdrawAddressValid}
|
disabled={!withdrawAddressValid}
|
||||||
|
@ -65,10 +69,6 @@ export default function WithdrawDialog({
|
||||||
>
|
>
|
||||||
Withdraw
|
Withdraw
|
||||||
</PromiseInvokeButton>
|
</PromiseInvokeButton>
|
||||||
) : (
|
|
||||||
<Button onClick={onCancel} color="primary" disabled={pending}>
|
|
||||||
Close
|
|
||||||
</Button>
|
|
||||||
)}
|
)}
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
|
@ -1,27 +1,31 @@
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from "react";
|
||||||
import { Box, DialogContent, makeStyles } from '@material-ui/core';
|
import { Box, DialogContent, makeStyles } from "@material-ui/core";
|
||||||
import WithdrawStepper from './WithdrawStepper';
|
import WithdrawStepper from "./WithdrawStepper";
|
||||||
|
|
||||||
const useStyles = makeStyles({
|
const useStyles = makeStyles({
|
||||||
outer: {
|
outer: {
|
||||||
minHeight: '15rem',
|
minHeight: "15rem",
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
justifyContent: 'space-between',
|
justifyContent: "space-between",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default function WithdrawDialogContent({
|
export default function WithdrawDialogContent({
|
||||||
children,
|
children,
|
||||||
|
isPending,
|
||||||
|
withdrawTxId,
|
||||||
}: {
|
}: {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
|
isPending: boolean;
|
||||||
|
withdrawTxId: string | null;
|
||||||
}) {
|
}) {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DialogContent dividers className={classes.outer}>
|
<DialogContent dividers className={classes.outer}>
|
||||||
<Box>{children}</Box>
|
<Box>{children}</Box>
|
||||||
<WithdrawStepper />
|
<WithdrawStepper isPending={isPending} withdrawTxId={withdrawTxId} />
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
import { useAppSelector, useIsRpcEndpointBusy } from 'store/hooks';
|
|
||||||
import { RpcMethod } from 'models/rpcModel';
|
|
||||||
import AddressInputPage from './pages/AddressInputPage';
|
|
||||||
import InitiatedPage from './pages/InitiatedPage';
|
|
||||||
import BtcTxInMempoolPageContent from './pages/BitcoinWithdrawTxInMempoolPage';
|
|
||||||
|
|
||||||
export default function WithdrawStatePage({
|
|
||||||
onCancel,
|
|
||||||
}: {
|
|
||||||
onCancel: () => void;
|
|
||||||
}) {
|
|
||||||
const isRpcEndpointBusy = useIsRpcEndpointBusy(RpcMethod.WITHDRAW_BTC);
|
|
||||||
const withdrawTxId = useAppSelector((state) => state.rpc.state.withdrawTxId);
|
|
||||||
|
|
||||||
if (withdrawTxId !== null) {
|
|
||||||
return (
|
|
||||||
<BtcTxInMempoolPageContent
|
|
||||||
withdrawTxId={withdrawTxId}
|
|
||||||
onCancel={onCancel}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (isRpcEndpointBusy) {
|
|
||||||
return <InitiatedPage onCancel={onCancel} />;
|
|
||||||
}
|
|
||||||
return <AddressInputPage onCancel={onCancel} />;
|
|
||||||
}
|
|
|
@ -1,12 +1,8 @@
|
||||||
import { Step, StepLabel, Stepper } from '@material-ui/core';
|
import { Step, StepLabel, Stepper } from "@material-ui/core";
|
||||||
import { useAppSelector, useIsRpcEndpointBusy } from 'store/hooks';
|
import { useAppSelector, useIsRpcEndpointBusy } from "store/hooks";
|
||||||
import { RpcMethod } from 'models/rpcModel';
|
|
||||||
|
|
||||||
function getActiveStep(
|
function getActiveStep(isPending: boolean, withdrawTxId: string | null) {
|
||||||
isWithdrawInProgress: boolean,
|
if (isPending) {
|
||||||
withdrawTxId: string | null,
|
|
||||||
) {
|
|
||||||
if (isWithdrawInProgress) {
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (withdrawTxId !== null) {
|
if (withdrawTxId !== null) {
|
||||||
|
@ -15,12 +11,15 @@ function getActiveStep(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function WithdrawStepper() {
|
export default function WithdrawStepper({
|
||||||
const isWithdrawInProgress = useIsRpcEndpointBusy(RpcMethod.WITHDRAW_BTC);
|
isPending,
|
||||||
const withdrawTxId = useAppSelector((s) => s.rpc.state.withdrawTxId);
|
withdrawTxId,
|
||||||
|
}: {
|
||||||
|
isPending: boolean;
|
||||||
|
withdrawTxId: string | null;
|
||||||
|
}) {
|
||||||
return (
|
return (
|
||||||
<Stepper activeStep={getActiveStep(isWithdrawInProgress, withdrawTxId)}>
|
<Stepper activeStep={getActiveStep(isPending, withdrawTxId)}>
|
||||||
<Step key={0}>
|
<Step key={0}>
|
||||||
<StepLabel>Enter withdraw address</StepLabel>
|
<StepLabel>Enter withdraw address</StepLabel>
|
||||||
</Step>
|
</Step>
|
||||||
|
|
|
@ -15,10 +15,9 @@ export default function AddressInputPage({
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<WithdrawDialogContent>
|
|
||||||
<DialogContentText>
|
<DialogContentText>
|
||||||
To withdraw the BTC of the internal wallet, please enter an address.
|
To withdraw the Bitcoin inside the internal wallet, please enter an
|
||||||
All funds will be sent to that address.
|
address. All funds will be sent to that address.
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
|
|
||||||
<BitcoinAddressTextField
|
<BitcoinAddressTextField
|
||||||
|
@ -28,7 +27,6 @@ export default function AddressInputPage({
|
||||||
helperText="All Bitcoin of the internal wallet will be transferred to this address"
|
helperText="All Bitcoin of the internal wallet will be transferred to this address"
|
||||||
fullWidth
|
fullWidth
|
||||||
/>
|
/>
|
||||||
</WithdrawDialogContent>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ export default function BtcTxInMempoolPageContent({
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<WithdrawDialogContent>
|
|
||||||
<DialogContentText>
|
<DialogContentText>
|
||||||
All funds of the internal Bitcoin wallet have been transferred to your
|
All funds of the internal Bitcoin wallet have been transferred to your
|
||||||
withdraw address.
|
withdraw address.
|
||||||
|
@ -22,7 +21,6 @@ export default function BtcTxInMempoolPageContent({
|
||||||
title="Bitcoin Withdraw Transaction"
|
title="Bitcoin Withdraw Transaction"
|
||||||
additionalContent={null}
|
additionalContent={null}
|
||||||
/>
|
/>
|
||||||
</WithdrawDialogContent>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Drawer, makeStyles, Box } from '@material-ui/core';
|
import { Drawer, makeStyles, Box } from "@material-ui/core";
|
||||||
import NavigationHeader from './NavigationHeader';
|
import NavigationHeader from "./NavigationHeader";
|
||||||
import NavigationFooter from './NavigationFooter';
|
import NavigationFooter from "./NavigationFooter";
|
||||||
|
|
||||||
export const drawerWidth = 240;
|
export const drawerWidth = 240;
|
||||||
|
|
||||||
|
@ -13,11 +13,11 @@ const useStyles = makeStyles({
|
||||||
width: drawerWidth,
|
width: drawerWidth,
|
||||||
},
|
},
|
||||||
drawerContainer: {
|
drawerContainer: {
|
||||||
overflow: 'auto',
|
overflow: "auto",
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
justifyContent: 'space-between',
|
justifyContent: "space-between",
|
||||||
height: '100%',
|
height: "100%",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
import RedditIcon from '@material-ui/icons/Reddit';
|
import RedditIcon from "@material-ui/icons/Reddit";
|
||||||
import GitHubIcon from '@material-ui/icons/GitHub';
|
import GitHubIcon from "@material-ui/icons/GitHub";
|
||||||
import { Box, makeStyles } from '@material-ui/core';
|
import { Box, makeStyles } from "@material-ui/core";
|
||||||
import LinkIconButton from '../icons/LinkIconButton';
|
import LinkIconButton from "../icons/LinkIconButton";
|
||||||
import UnfinishedSwapsAlert from '../alert/UnfinishedSwapsAlert';
|
import UnfinishedSwapsAlert from "../alert/UnfinishedSwapsAlert";
|
||||||
import FundsLeftInWalletAlert from '../alert/FundsLeftInWalletAlert';
|
import FundsLeftInWalletAlert from "../alert/FundsLeftInWalletAlert";
|
||||||
import RpcStatusAlert from '../alert/RpcStatusAlert';
|
import RpcStatusAlert from "../alert/RpcStatusAlert";
|
||||||
import DiscordIcon from '../icons/DiscordIcon';
|
import DiscordIcon from "../icons/DiscordIcon";
|
||||||
import { DISCORD_URL } from '../pages/help/ContactInfoBox';
|
import { DISCORD_URL } from "../pages/help/ContactInfoBox";
|
||||||
import MoneroWalletRpcUpdatingAlert from '../alert/MoneroWalletRpcUpdatingAlert';
|
import MoneroWalletRpcUpdatingAlert from "../alert/MoneroWalletRpcUpdatingAlert";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
outer: {
|
outer: {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
padding: theme.spacing(1),
|
padding: theme.spacing(1),
|
||||||
gap: theme.spacing(1),
|
gap: theme.spacing(1),
|
||||||
},
|
},
|
||||||
linksOuter: {
|
linksOuter: {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
justifyContent: 'space-evenly',
|
justifyContent: "space-evenly",
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { Box, List } from '@material-ui/core';
|
import { Box, List } from "@material-ui/core";
|
||||||
import SwapHorizOutlinedIcon from '@material-ui/icons/SwapHorizOutlined';
|
import SwapHorizOutlinedIcon from "@material-ui/icons/SwapHorizOutlined";
|
||||||
import HistoryOutlinedIcon from '@material-ui/icons/HistoryOutlined';
|
import HistoryOutlinedIcon from "@material-ui/icons/HistoryOutlined";
|
||||||
import AccountBalanceWalletIcon from '@material-ui/icons/AccountBalanceWallet';
|
import AccountBalanceWalletIcon from "@material-ui/icons/AccountBalanceWallet";
|
||||||
import HelpOutlineIcon from '@material-ui/icons/HelpOutline';
|
import HelpOutlineIcon from "@material-ui/icons/HelpOutline";
|
||||||
import RouteListItemIconButton from './RouteListItemIconButton';
|
import RouteListItemIconButton from "./RouteListItemIconButton";
|
||||||
import UnfinishedSwapsBadge from './UnfinishedSwapsCountBadge';
|
import UnfinishedSwapsBadge from "./UnfinishedSwapsCountBadge";
|
||||||
|
|
||||||
export default function NavigationHeader() {
|
export default function NavigationHeader() {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from "react";
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from "react-router-dom";
|
||||||
import { ListItem, ListItemIcon, ListItemText } from '@material-ui/core';
|
import { ListItem, ListItemIcon, ListItemText } from "@material-ui/core";
|
||||||
|
|
||||||
export default function RouteListItemIconButton({
|
export default function RouteListItemIconButton({
|
||||||
name,
|
name,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Badge } from '@material-ui/core';
|
import { Badge } from "@material-ui/core";
|
||||||
import { useResumeableSwapsCount } from 'store/hooks';
|
import { useResumeableSwapsCount } from "store/hooks";
|
||||||
|
|
||||||
export default function UnfinishedSwapsBadge({
|
export default function UnfinishedSwapsBadge({
|
||||||
children,
|
children,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { useState } from 'react';
|
import { useState } from "react";
|
||||||
import { Box, IconButton, TextField } from '@material-ui/core';
|
import { Box, IconButton, TextField } from "@material-ui/core";
|
||||||
import SearchIcon from '@material-ui/icons/Search';
|
import SearchIcon from "@material-ui/icons/Search";
|
||||||
import CloseIcon from '@material-ui/icons/Close';
|
import CloseIcon from "@material-ui/icons/Close";
|
||||||
|
|
||||||
export function ExpandableSearchBox({
|
export function ExpandableSearchBox({
|
||||||
query,
|
query,
|
||||||
|
@ -13,8 +13,8 @@ export function ExpandableSearchBox({
|
||||||
const [expanded, setExpanded] = useState(false);
|
const [expanded, setExpanded] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box style={{ display: 'flex', justifyContent: 'center' }}>
|
<Box style={{ display: "flex", justifyContent: "center" }}>
|
||||||
<Box style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
|
<Box style={{ display: "flex", alignItems: "center", gap: "0.5rem" }}>
|
||||||
{expanded ? (
|
{expanded ? (
|
||||||
<>
|
<>
|
||||||
<TextField
|
<TextField
|
||||||
|
@ -26,7 +26,7 @@ export function ExpandableSearchBox({
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setExpanded(false);
|
setExpanded(false);
|
||||||
setQuery('');
|
setQuery("");
|
||||||
}}
|
}}
|
||||||
size="small"
|
size="small"
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import humanizeDuration from 'humanize-duration';
|
import humanizeDuration from "humanize-duration";
|
||||||
|
|
||||||
const AVG_BLOCK_TIME_MS = 10 * 60 * 1000;
|
const AVG_BLOCK_TIME_MS = 10 * 60 * 1000;
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ export default function HumanizedBitcoinBlockDuration({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{`${humanizeDuration(blocks * AVG_BLOCK_TIME_MS, {
|
{`${humanizeDuration(blocks * AVG_BLOCK_TIME_MS, {
|
||||||
conjunction: ' and ',
|
conjunction: " and ",
|
||||||
})} (${blocks} blocks)`}
|
})} (${blocks} blocks)`}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import TreeView from '@material-ui/lab/TreeView';
|
import TreeView from "@material-ui/lab/TreeView";
|
||||||
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
||||||
import ChevronRightIcon from '@material-ui/icons/ChevronRight';
|
import ChevronRightIcon from "@material-ui/icons/ChevronRight";
|
||||||
import TreeItem from '@material-ui/lab/TreeItem';
|
import TreeItem from "@material-ui/lab/TreeItem";
|
||||||
import ScrollablePaperTextBox from './ScrollablePaperTextBox';
|
import ScrollablePaperTextBox from "./ScrollablePaperTextBox";
|
||||||
|
|
||||||
interface JsonTreeViewProps {
|
interface JsonTreeViewProps {
|
||||||
data: any;
|
data: any;
|
||||||
|
@ -13,7 +13,7 @@ export default function JsonTreeView({ data, label }: JsonTreeViewProps) {
|
||||||
const renderTree = (nodes: any, parentId: string) => {
|
const renderTree = (nodes: any, parentId: string) => {
|
||||||
return Object.keys(nodes).map((key, _) => {
|
return Object.keys(nodes).map((key, _) => {
|
||||||
const nodeId = `${parentId}.${key}`;
|
const nodeId = `${parentId}.${key}`;
|
||||||
if (typeof nodes[key] === 'object' && nodes[key] !== null) {
|
if (typeof nodes[key] === "object" && nodes[key] !== null) {
|
||||||
return (
|
return (
|
||||||
<TreeItem nodeId={nodeId} label={key} key={nodeId}>
|
<TreeItem nodeId={nodeId} label={key} key={nodeId}>
|
||||||
{renderTree(nodes[key], nodeId)}
|
{renderTree(nodes[key], nodeId)}
|
||||||
|
@ -38,10 +38,10 @@ export default function JsonTreeView({ data, label }: JsonTreeViewProps) {
|
||||||
<TreeView
|
<TreeView
|
||||||
defaultCollapseIcon={<ExpandMoreIcon />}
|
defaultCollapseIcon={<ExpandMoreIcon />}
|
||||||
defaultExpandIcon={<ChevronRightIcon />}
|
defaultExpandIcon={<ChevronRightIcon />}
|
||||||
defaultExpanded={['root']}
|
defaultExpanded={["root"]}
|
||||||
>
|
>
|
||||||
<TreeItem nodeId="root" label={label}>
|
<TreeItem nodeId="root" label={label}>
|
||||||
{renderTree(data ?? {}, 'root')}
|
{renderTree(data ?? {}, "root")}
|
||||||
</TreeItem>
|
</TreeItem>
|
||||||
</TreeView>,
|
</TreeView>,
|
||||||
]}
|
]}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from "react";
|
||||||
import Button, { ButtonProps } from '@material-ui/core/Button';
|
import Button, { ButtonProps } from "@material-ui/core/Button";
|
||||||
import CircularProgress from '@material-ui/core/CircularProgress';
|
import CircularProgress from "@material-ui/core/CircularProgress";
|
||||||
|
|
||||||
interface LoadingButtonProps extends ButtonProps {
|
interface LoadingButtonProps extends ButtonProps {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
|
|
|
@ -1,47 +1,47 @@
|
||||||
import { Box, Chip, Typography } from '@material-ui/core';
|
import { Box, Chip, Typography } from "@material-ui/core";
|
||||||
import { useMemo, useState } from 'react';
|
import { useMemo, useState } from "react";
|
||||||
import { CliLog } from 'models/cliModel';
|
import { CliLog } from "models/cliModel";
|
||||||
import { logsToRawString } from 'utils/parseUtils';
|
import { logsToRawString } from "utils/parseUtils";
|
||||||
import ScrollablePaperTextBox from './ScrollablePaperTextBox';
|
import ScrollablePaperTextBox from "./ScrollablePaperTextBox";
|
||||||
|
|
||||||
function RenderedCliLog({ log }: { log: CliLog }) {
|
function RenderedCliLog({ log }: { log: CliLog }) {
|
||||||
const { timestamp, level, fields } = log;
|
const { timestamp, level, fields } = log;
|
||||||
|
|
||||||
const levelColorMap = {
|
const levelColorMap = {
|
||||||
DEBUG: '#1976d2', // Blue
|
DEBUG: "#1976d2", // Blue
|
||||||
INFO: '#388e3c', // Green
|
INFO: "#388e3c", // Green
|
||||||
WARN: '#fbc02d', // Yellow
|
WARN: "#fbc02d", // Yellow
|
||||||
ERROR: '#d32f2f', // Red
|
ERROR: "#d32f2f", // Red
|
||||||
TRACE: '#8e24aa', // Purple
|
TRACE: "#8e24aa", // Purple
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: '0.3rem',
|
gap: "0.3rem",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Chip
|
<Chip
|
||||||
label={level}
|
label={level}
|
||||||
size="small"
|
size="small"
|
||||||
style={{ backgroundColor: levelColorMap[level], color: 'white' }}
|
style={{ backgroundColor: levelColorMap[level], color: "white" }}
|
||||||
/>
|
/>
|
||||||
<Chip label={timestamp} size="small" variant="outlined" />
|
<Chip label={timestamp} size="small" variant="outlined" />
|
||||||
<Typography variant="subtitle2">{fields.message}</Typography>
|
<Typography variant="subtitle2">{fields.message}</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
paddingLeft: '1rem',
|
paddingLeft: "1rem",
|
||||||
paddingTop: '0.2rem',
|
paddingTop: "0.2rem",
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Object.entries(fields).map(([key, value]) => {
|
{Object.entries(fields).map(([key, value]) => {
|
||||||
if (key !== 'message') {
|
if (key !== "message") {
|
||||||
return (
|
return (
|
||||||
<Typography variant="caption" key={key}>
|
<Typography variant="caption" key={key}>
|
||||||
{key}: {JSON.stringify(value)}
|
{key}: {JSON.stringify(value)}
|
||||||
|
@ -62,7 +62,7 @@ export default function CliLogsBox({
|
||||||
label: string;
|
label: string;
|
||||||
logs: (CliLog | string)[];
|
logs: (CliLog | string)[];
|
||||||
}) {
|
}) {
|
||||||
const [searchQuery, setSearchQuery] = useState<string>('');
|
const [searchQuery, setSearchQuery] = useState<string>("");
|
||||||
|
|
||||||
const memoizedLogs = useMemo(() => {
|
const memoizedLogs = useMemo(() => {
|
||||||
if (searchQuery.length === 0) {
|
if (searchQuery.length === 0) {
|
||||||
|
@ -80,7 +80,7 @@ export default function CliLogsBox({
|
||||||
searchQuery={searchQuery}
|
searchQuery={searchQuery}
|
||||||
setSearchQuery={setSearchQuery}
|
setSearchQuery={setSearchQuery}
|
||||||
rows={memoizedLogs.map((log) =>
|
rows={memoizedLogs.map((log) =>
|
||||||
typeof log === 'string' ? (
|
typeof log === "string" ? (
|
||||||
<Typography component="pre">{log}</Typography>
|
<Typography component="pre">{log}</Typography>
|
||||||
) : (
|
) : (
|
||||||
<RenderedCliLog log={log} key={JSON.stringify(log)} />
|
<RenderedCliLog log={log} key={JSON.stringify(log)} />
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { Box, Divider, IconButton, Paper, Typography } from '@material-ui/core';
|
import { Box, Divider, IconButton, Paper, Typography } from "@material-ui/core";
|
||||||
import { ReactNode, useRef } from 'react';
|
import { ReactNode, useRef } from "react";
|
||||||
import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
|
import KeyboardArrowDownIcon from "@material-ui/icons/KeyboardArrowDown";
|
||||||
import KeyboardArrowUpIcon from '@material-ui/icons/KeyboardArrowUp';
|
import KeyboardArrowUpIcon from "@material-ui/icons/KeyboardArrowUp";
|
||||||
import { VList, VListHandle } from 'virtua';
|
import { VList, VListHandle } from "virtua";
|
||||||
import FileCopyOutlinedIcon from '@material-ui/icons/FileCopyOutlined';
|
import FileCopyOutlinedIcon from "@material-ui/icons/FileCopyOutlined";
|
||||||
import { ExpandableSearchBox } from './ExpandableSearchBox';
|
import { ExpandableSearchBox } from "./ExpandableSearchBox";
|
||||||
|
|
||||||
const MIN_HEIGHT = '10rem';
|
const MIN_HEIGHT = "10rem";
|
||||||
|
|
||||||
export default function ScrollablePaperTextBox({
|
export default function ScrollablePaperTextBox({
|
||||||
rows,
|
rows,
|
||||||
|
@ -41,31 +41,31 @@ export default function ScrollablePaperTextBox({
|
||||||
<Paper
|
<Paper
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
gap: '0.5rem',
|
gap: "0.5rem",
|
||||||
padding: '0.5rem',
|
padding: "0.5rem",
|
||||||
width: '100%',
|
width: "100%",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography>{title}</Typography>
|
<Typography>{title}</Typography>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
overflow: 'auto',
|
overflow: "auto",
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: "nowrap",
|
||||||
maxHeight: minHeight,
|
maxHeight: minHeight,
|
||||||
minHeight,
|
minHeight,
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
gap: '0.5rem',
|
gap: "0.5rem",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<VList ref={virtuaEl} style={{ height: MIN_HEIGHT, width: '100%' }}>
|
<VList ref={virtuaEl} style={{ height: MIN_HEIGHT, width: "100%" }}>
|
||||||
{rows}
|
{rows}
|
||||||
</VList>
|
</VList>
|
||||||
</Box>
|
</Box>
|
||||||
<Box style={{ display: 'flex', gap: '0.5rem' }}>
|
<Box style={{ display: "flex", gap: "0.5rem" }}>
|
||||||
<IconButton onClick={onCopy} size="small">
|
<IconButton onClick={onCopy} size="small">
|
||||||
<FileCopyOutlinedIcon />
|
<FileCopyOutlinedIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
import { Box, Button, makeStyles, Typography } from '@material-ui/core';
|
import { Box, Button, makeStyles, Typography } from "@material-ui/core";
|
||||||
import InfoBox from '../../modal/swap/InfoBox';
|
import InfoBox from "../../modal/swap/InfoBox";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
spacedBox: {
|
spacedBox: {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: theme.spacing(1),
|
gap: theme.spacing(1),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const GITHUB_ISSUE_URL =
|
const GITHUB_ISSUE_URL =
|
||||||
'https://github.com/UnstoppableSwap/unstoppableswap-gui/issues/new/choose';
|
"https://github.com/UnstoppableSwap/unstoppableswap-gui/issues/new/choose";
|
||||||
const MATRIX_ROOM_URL = 'https://matrix.to/#/#unstoppableswap:matrix.org';
|
const MATRIX_ROOM_URL = "https://matrix.to/#/#unstoppableswap:matrix.org";
|
||||||
export const DISCORD_URL = 'https://discord.gg/APJ6rJmq';
|
export const DISCORD_URL = "https://discord.gg/APJ6rJmq";
|
||||||
|
|
||||||
export default function ContactInfoBox() {
|
export default function ContactInfoBox() {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { Typography } from '@material-ui/core';
|
import { Typography } from "@material-ui/core";
|
||||||
import DepositAddressInfoBox from '../../modal/swap/DepositAddressInfoBox';
|
import DepositAddressInfoBox from "../../modal/swap/DepositAddressInfoBox";
|
||||||
import MoneroIcon from '../../icons/MoneroIcon';
|
import MoneroIcon from "../../icons/MoneroIcon";
|
||||||
|
|
||||||
const XMR_DONATE_ADDRESS =
|
const XMR_DONATE_ADDRESS =
|
||||||
'87jS4C7ngk9EHdqFFuxGFgg8AyH63dRUoULshWDybFJaP75UA89qsutG5B1L1QTc4w228nsqsv8EjhL7bz8fB3611Mh98mg';
|
"87jS4C7ngk9EHdqFFuxGFgg8AyH63dRUoULshWDybFJaP75UA89qsutG5B1L1QTc4w228nsqsv8EjhL7bz8fB3611Mh98mg";
|
||||||
|
|
||||||
export default function DonateInfoBox() {
|
export default function DonateInfoBox() {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Button, Typography } from '@material-ui/core';
|
import { Button, Typography } from "@material-ui/core";
|
||||||
import { useState } from 'react';
|
import { useState } from "react";
|
||||||
import InfoBox from '../../modal/swap/InfoBox';
|
import InfoBox from "../../modal/swap/InfoBox";
|
||||||
import FeedbackDialog from '../../modal/feedback/FeedbackDialog';
|
import FeedbackDialog from "../../modal/feedback/FeedbackDialog";
|
||||||
|
|
||||||
export default function FeedbackInfoBox() {
|
export default function FeedbackInfoBox() {
|
||||||
const [showDialog, setShowDialog] = useState(false);
|
const [showDialog, setShowDialog] = useState(false);
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
import { Box, makeStyles } from '@material-ui/core';
|
import { Box, makeStyles } from "@material-ui/core";
|
||||||
import ContactInfoBox from './ContactInfoBox';
|
import ContactInfoBox from "./ContactInfoBox";
|
||||||
import FeedbackInfoBox from './FeedbackInfoBox';
|
import FeedbackInfoBox from "./FeedbackInfoBox";
|
||||||
import DonateInfoBox from './DonateInfoBox';
|
import DonateInfoBox from "./DonateInfoBox";
|
||||||
import TorInfoBox from './TorInfoBox';
|
import TorInfoBox from "./TorInfoBox";
|
||||||
import RpcControlBox from './RpcControlBox';
|
import RpcControlBox from "./RpcControlBox";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
outer: {
|
outer: {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: theme.spacing(2),
|
gap: theme.spacing(2),
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import { Box, makeStyles } from '@material-ui/core';
|
import { Box, makeStyles } from "@material-ui/core";
|
||||||
import IpcInvokeButton from 'renderer/components/IpcInvokeButton';
|
import IpcInvokeButton from "renderer/components/IpcInvokeButton";
|
||||||
import { useAppSelector } from 'store/hooks';
|
import { useAppSelector } from "store/hooks";
|
||||||
import StopIcon from '@material-ui/icons/Stop';
|
import StopIcon from "@material-ui/icons/Stop";
|
||||||
import PlayArrowIcon from '@material-ui/icons/PlayArrow';
|
import PlayArrowIcon from "@material-ui/icons/PlayArrow";
|
||||||
import { RpcProcessStateType } from 'models/rpcModel';
|
import { RpcProcessStateType } from "models/rpcModel";
|
||||||
import InfoBox from '../../modal/swap/InfoBox';
|
import InfoBox from "../../modal/swap/InfoBox";
|
||||||
import CliLogsBox from '../../other/RenderedCliLog';
|
import CliLogsBox from "../../other/RenderedCliLog";
|
||||||
import FolderOpenIcon from '@material-ui/icons/FolderOpen';
|
import FolderOpenIcon from "@material-ui/icons/FolderOpen";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
actionsOuter: {
|
actionsOuter: {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: theme.spacing(1),
|
gap: theme.spacing(1),
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import { Box, makeStyles, Typography } from '@material-ui/core';
|
import { Box, makeStyles, Typography } from "@material-ui/core";
|
||||||
import IpcInvokeButton from 'renderer/components/IpcInvokeButton';
|
import IpcInvokeButton from "renderer/components/IpcInvokeButton";
|
||||||
import { useAppSelector } from 'store/hooks';
|
import { useAppSelector } from "store/hooks";
|
||||||
import StopIcon from '@material-ui/icons/Stop';
|
import StopIcon from "@material-ui/icons/Stop";
|
||||||
import PlayArrowIcon from '@material-ui/icons/PlayArrow';
|
import PlayArrowIcon from "@material-ui/icons/PlayArrow";
|
||||||
import InfoBox from '../../modal/swap/InfoBox';
|
import InfoBox from "../../modal/swap/InfoBox";
|
||||||
import CliLogsBox from '../../other/RenderedCliLog';
|
import CliLogsBox from "../../other/RenderedCliLog";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
actionsOuter: {
|
actionsOuter: {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: theme.spacing(1),
|
gap: theme.spacing(1),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
@ -24,10 +24,10 @@ export default function TorInfoBox() {
|
||||||
mainContent={
|
mainContent={
|
||||||
<Box
|
<Box
|
||||||
style={{
|
style={{
|
||||||
width: '100%',
|
width: "100%",
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
gap: '8px',
|
gap: "8px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography variant="subtitle2">
|
<Typography variant="subtitle2">
|
||||||
|
@ -37,7 +37,7 @@ export default function TorInfoBox() {
|
||||||
below. If Tor is running, all traffic will be routed through it and
|
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.
|
the swap provider will not be able to see your IP address.
|
||||||
</Typography>
|
</Typography>
|
||||||
<CliLogsBox label="Tor Daemon Logs" logs={torStdOut.split('\n')} />
|
<CliLogsBox label="Tor Daemon Logs" logs={torStdOut.split("\n")} />
|
||||||
</Box>
|
</Box>
|
||||||
}
|
}
|
||||||
additionalContent={
|
additionalContent={
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { Typography } from '@material-ui/core';
|
import { Typography } from "@material-ui/core";
|
||||||
import { useIsSwapRunning } from 'store/hooks';
|
import { useIsSwapRunning } from "store/hooks";
|
||||||
import HistoryTable from './table/HistoryTable';
|
import HistoryTable from "./table/HistoryTable";
|
||||||
import SwapDialog from '../../modal/swap/SwapDialog';
|
import SwapDialog from "../../modal/swap/SwapDialog";
|
||||||
import SwapTxLockAlertsBox from '../../alert/SwapTxLockAlertsBox';
|
import SwapTxLockAlertsBox from "../../alert/SwapTxLockAlertsBox";
|
||||||
|
|
||||||
export default function HistoryPage() {
|
export default function HistoryPage() {
|
||||||
const showDialog = useIsSwapRunning();
|
const showDialog = useIsSwapRunning();
|
||||||
|
|
|
@ -60,27 +60,15 @@ export default function HistoryRow({ swap }: HistoryRowProps) {
|
||||||
<>
|
<>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<IconButton
|
<IconButton size="small" onClick={() => setExpanded(!expanded)}>
|
||||||
size="small"
|
{expanded ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
|
||||||
onClick={() => setExpanded(!expanded)}
|
|
||||||
>
|
|
||||||
{expanded ? (
|
|
||||||
<KeyboardArrowUpIcon />
|
|
||||||
) : (
|
|
||||||
<KeyboardArrowDownIcon />
|
|
||||||
)}
|
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>{swap.swap_id.substring(0, 5)}...</TableCell>
|
<TableCell>{swap.swap_id.substring(0, 5)}...</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<AmountTransfer
|
<AmountTransfer xmrAmount={xmrAmount} btcAmount={btcAmount} />
|
||||||
xmrAmount={xmrAmount}
|
|
||||||
btcAmount={btcAmount}
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell>
|
|
||||||
{getHumanReadableDbStateType(swap.state_name)}
|
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
<TableCell>{getHumanReadableDbStateType(swap.state_name)}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<HistoryRowActions swap={swap} />
|
<HistoryRowActions swap={swap} />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|
|
@ -87,9 +87,7 @@ export default function HistoryRowExpanded({
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell>Exchange Rate</TableCell>
|
<TableCell>Exchange Rate</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<MoneroBitcoinExchangeRate
|
<MoneroBitcoinExchangeRate rate={exchangeRate} />
|
||||||
rate={exchangeRate}
|
|
||||||
/>
|
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
|
@ -108,10 +106,7 @@ export default function HistoryRowExpanded({
|
||||||
<TableCell>Bitcoin lock transaction</TableCell>
|
<TableCell>Bitcoin lock transaction</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<Link
|
<Link
|
||||||
href={getBitcoinTxExplorerUrl(
|
href={getBitcoinTxExplorerUrl(swap.tx_lock_id, isTestnet())}
|
||||||
swap.tx_lock_id,
|
|
||||||
isTestnet(),
|
|
||||||
)}
|
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
{swap.tx_lock_id}
|
{swap.tx_lock_id}
|
||||||
|
@ -127,11 +122,7 @@ export default function HistoryRowExpanded({
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
size="small"
|
size="small"
|
||||||
/>
|
/>
|
||||||
<SwapCancelRefundButton
|
<SwapCancelRefundButton swap={swap} variant="contained" size="small" />
|
||||||
swap={swap}
|
|
||||||
variant="contained"
|
|
||||||
size="small"
|
|
||||||
/>
|
|
||||||
<SwapMoneroRecoveryButton
|
<SwapMoneroRecoveryButton
|
||||||
swap={swap}
|
swap={swap}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
import { ButtonProps } from '@material-ui/core/Button/Button';
|
import { ButtonProps } from "@material-ui/core/Button/Button";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogActions,
|
DialogActions,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from '@material-ui/core';
|
} from "@material-ui/core";
|
||||||
import { useState } from 'react';
|
import { useState } from "react";
|
||||||
import { CliLog } from 'models/cliModel';
|
import { CliLog } from "models/cliModel";
|
||||||
import IpcInvokeButton from '../../../IpcInvokeButton';
|
import IpcInvokeButton from "../../../IpcInvokeButton";
|
||||||
import CliLogsBox from '../../../other/RenderedCliLog';
|
import CliLogsBox from "../../../other/RenderedCliLog";
|
||||||
|
|
||||||
export default function SwapLogFileOpenButton({
|
export default function SwapLogFileOpenButton({
|
||||||
swapId,
|
swapId,
|
||||||
|
|
|
@ -37,17 +37,16 @@ function MoneroRecoveryKeysDialog({ swap }: { swap: GetSwapInfoResponse }) {
|
||||||
/>
|
/>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogContentText>
|
<DialogContentText>
|
||||||
You can use the keys below to manually redeem the Monero
|
You can use the keys below to manually redeem the Monero funds from
|
||||||
funds from the multi-signature wallet.
|
the multi-signature wallet.
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
This is useful if the swap daemon fails to redeem
|
This is useful if the swap daemon fails to redeem the funds itself
|
||||||
the funds itself
|
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
If you have come this far, there is no risk of
|
If you have come this far, there is no risk of losing funds. You
|
||||||
losing funds. You are the only one with access to
|
are the only one with access to these keys and can use them to
|
||||||
these keys and can use them to access your funds
|
access your funds
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
View{" "}
|
View{" "}
|
||||||
|
@ -58,8 +57,8 @@ function MoneroRecoveryKeysDialog({ swap }: { swap: GetSwapInfoResponse }) {
|
||||||
>
|
>
|
||||||
this guide
|
this guide
|
||||||
</Link>{" "}
|
</Link>{" "}
|
||||||
for a detailed description on how to import the keys
|
for a detailed description on how to import the keys and spend the
|
||||||
and spend the funds.
|
funds.
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Box } from '@material-ui/core';
|
import { Box } from "@material-ui/core";
|
||||||
import { Alert, AlertTitle } from '@material-ui/lab';
|
import { Alert, AlertTitle } from "@material-ui/lab";
|
||||||
import { removeAlert } from 'store/features/alertsSlice';
|
import { removeAlert } from "store/features/alertsSlice";
|
||||||
import { useAppDispatch, useAppSelector } from 'store/hooks';
|
import { useAppDispatch, useAppSelector } from "store/hooks";
|
||||||
|
|
||||||
export default function ApiAlertsBox() {
|
export default function ApiAlertsBox() {
|
||||||
const alerts = useAppSelector((state) => state.alerts.alerts);
|
const alerts = useAppSelector((state) => state.alerts.alerts);
|
||||||
|
@ -14,7 +14,7 @@ export default function ApiAlertsBox() {
|
||||||
if (alerts.length === 0) return null;
|
if (alerts.length === 0) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box style={{ display: 'flex', justifyContent: 'center', gap: '1rem' }}>
|
<Box style={{ display: "flex", justifyContent: "center", gap: "1rem" }}>
|
||||||
{alerts.map((alert) => (
|
{alerts.map((alert) => (
|
||||||
<Alert
|
<Alert
|
||||||
variant="filled"
|
variant="filled"
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { Box, makeStyles } from '@material-ui/core';
|
import { Box, makeStyles } from "@material-ui/core";
|
||||||
import SwapWidget from './SwapWidget';
|
import SwapWidget from "./SwapWidget";
|
||||||
import ApiAlertsBox from './ApiAlertsBox';
|
import ApiAlertsBox from "./ApiAlertsBox";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
outer: {
|
outer: {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
width: '100%',
|
width: "100%",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
paddingBottom: theme.spacing(1),
|
paddingBottom: theme.spacing(1),
|
||||||
gap: theme.spacing(1),
|
gap: theme.spacing(1),
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { ChangeEvent, useEffect, useState } from 'react';
|
import { ChangeEvent, useEffect, useState } from "react";
|
||||||
import {
|
import {
|
||||||
makeStyles,
|
makeStyles,
|
||||||
Box,
|
Box,
|
||||||
|
@ -7,21 +7,21 @@ import {
|
||||||
TextField,
|
TextField,
|
||||||
LinearProgress,
|
LinearProgress,
|
||||||
Fab,
|
Fab,
|
||||||
} from '@material-ui/core';
|
} from "@material-ui/core";
|
||||||
import InputAdornment from '@material-ui/core/InputAdornment';
|
import InputAdornment from "@material-ui/core/InputAdornment";
|
||||||
import ArrowDownwardIcon from '@material-ui/icons/ArrowDownward';
|
import ArrowDownwardIcon from "@material-ui/icons/ArrowDownward";
|
||||||
import SwapHorizIcon from '@material-ui/icons/SwapHoriz';
|
import SwapHorizIcon from "@material-ui/icons/SwapHoriz";
|
||||||
import { Alert } from '@material-ui/lab';
|
import { Alert } from "@material-ui/lab";
|
||||||
import { satsToBtc } from 'utils/conversionUtils';
|
import { satsToBtc } from "utils/conversionUtils";
|
||||||
import { useAppSelector } from 'store/hooks';
|
import { useAppSelector } from "store/hooks";
|
||||||
import { ExtendedProviderStatus } from 'models/apiModel';
|
import { ExtendedProviderStatus } from "models/apiModel";
|
||||||
import { isSwapState } from 'models/storeModel';
|
import { isSwapState } from "models/storeModel";
|
||||||
import SwapDialog from '../../modal/swap/SwapDialog';
|
import SwapDialog from "../../modal/swap/SwapDialog";
|
||||||
import ProviderSelect from '../../modal/provider/ProviderSelect';
|
import ProviderSelect from "../../modal/provider/ProviderSelect";
|
||||||
import {
|
import {
|
||||||
ListSellersDialogOpenButton,
|
ListSellersDialogOpenButton,
|
||||||
ProviderSubmitDialogOpenButton,
|
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
|
// After RECONNECTION_ATTEMPTS_UNTIL_ASSUME_DOWN failed reconnection attempts we can assume the public registry is down
|
||||||
const RECONNECTION_ATTEMPTS_UNTIL_ASSUME_DOWN = 1;
|
const RECONNECTION_ATTEMPTS_UNTIL_ASSUME_DOWN = 1;
|
||||||
|
@ -32,9 +32,9 @@ function isRegistryDown(reconnectionAttempts: number): boolean {
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
inner: {
|
inner: {
|
||||||
width: 'min(480px, 100%)',
|
width: "min(480px, 100%)",
|
||||||
minHeight: '150px',
|
minHeight: "150px",
|
||||||
display: 'grid',
|
display: "grid",
|
||||||
padding: theme.spacing(1),
|
padding: theme.spacing(1),
|
||||||
gridGap: theme.spacing(1),
|
gridGap: theme.spacing(1),
|
||||||
},
|
},
|
||||||
|
@ -48,19 +48,19 @@ const useStyles = makeStyles((theme) => ({
|
||||||
padding: theme.spacing(1),
|
padding: theme.spacing(1),
|
||||||
},
|
},
|
||||||
swapIconOuter: {
|
swapIconOuter: {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
justifyContent: 'center',
|
justifyContent: "center",
|
||||||
},
|
},
|
||||||
swapIcon: {
|
swapIcon: {
|
||||||
marginRight: theme.spacing(1),
|
marginRight: theme.spacing(1),
|
||||||
},
|
},
|
||||||
noProvidersAlertOuter: {
|
noProvidersAlertOuter: {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
gap: theme.spacing(1),
|
gap: theme.spacing(1),
|
||||||
},
|
},
|
||||||
noProvidersAlertButtonsOuter: {
|
noProvidersAlertButtonsOuter: {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: theme.spacing(1),
|
gap: theme.spacing(1),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
@ -111,7 +111,7 @@ function HasProviderSwapWidget({
|
||||||
function getBtcFieldError(): string | null {
|
function getBtcFieldError(): string | null {
|
||||||
const parsedBtcAmount = Number(btcFieldValue);
|
const parsedBtcAmount = Number(btcFieldValue);
|
||||||
if (Number.isNaN(parsedBtcAmount)) {
|
if (Number.isNaN(parsedBtcAmount)) {
|
||||||
return 'This is not a valid number';
|
return "This is not a valid number";
|
||||||
}
|
}
|
||||||
if (parsedBtcAmount < satsToBtc(selectedProvider.minSwapAmount)) {
|
if (parsedBtcAmount < satsToBtc(selectedProvider.minSwapAmount)) {
|
||||||
return `The minimum swap amount is ${satsToBtc(
|
return `The minimum swap amount is ${satsToBtc(
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { Box, makeStyles, Typography } from '@material-ui/core';
|
import { Box, makeStyles, Typography } from "@material-ui/core";
|
||||||
import { Alert } from '@material-ui/lab';
|
import { Alert } from "@material-ui/lab";
|
||||||
import WithdrawWidget from './WithdrawWidget';
|
import WithdrawWidget from "./WithdrawWidget";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
outer: {
|
outer: {
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
flexDirection: 'column',
|
flexDirection: "column",
|
||||||
gridGap: theme.spacing(0.5),
|
gridGap: theme.spacing(0.5),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import { Box, Button, makeStyles, Typography } from '@material-ui/core';
|
import { Box, Button, makeStyles, Typography } from "@material-ui/core";
|
||||||
import { useState } from 'react';
|
import { useState } from "react";
|
||||||
import SendIcon from '@material-ui/icons/Send';
|
import SendIcon from "@material-ui/icons/Send";
|
||||||
import { useAppSelector, useIsRpcEndpointBusy } from 'store/hooks';
|
import { useAppSelector, useIsRpcEndpointBusy } from "store/hooks";
|
||||||
import { RpcMethod } from 'models/rpcModel';
|
import { RpcMethod } from "models/rpcModel";
|
||||||
import BitcoinIcon from '../../icons/BitcoinIcon';
|
import BitcoinIcon from "../../icons/BitcoinIcon";
|
||||||
import WithdrawDialog from '../../modal/wallet/WithdrawDialog';
|
import WithdrawDialog from "../../modal/wallet/WithdrawDialog";
|
||||||
import WalletRefreshButton from './WalletRefreshButton';
|
import WalletRefreshButton from "./WalletRefreshButton";
|
||||||
import InfoBox from '../../modal/swap/InfoBox';
|
import InfoBox from "../../modal/swap/InfoBox";
|
||||||
import { SatsAmount } from 'renderer/components/other/Units';
|
import { SatsAmount } from "renderer/components/other/Units";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
title: {
|
title: {
|
||||||
alignItems: 'center',
|
alignItems: "center",
|
||||||
display: 'flex',
|
display: "flex",
|
||||||
gap: theme.spacing(0.5),
|
gap: theme.spacing(0.5),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -3,14 +3,14 @@ import {
|
||||||
SnackbarKey,
|
SnackbarKey,
|
||||||
SnackbarProvider,
|
SnackbarProvider,
|
||||||
useSnackbar,
|
useSnackbar,
|
||||||
} from 'notistack';
|
} from "notistack";
|
||||||
import { IconButton, styled } from '@material-ui/core';
|
import { IconButton, styled } from "@material-ui/core";
|
||||||
import { Close } from '@material-ui/icons';
|
import { Close } from "@material-ui/icons";
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from "react";
|
||||||
|
|
||||||
const StyledMaterialDesignContent = styled(MaterialDesignContent)(() => ({
|
const StyledMaterialDesignContent = styled(MaterialDesignContent)(() => ({
|
||||||
'&.notistack-MuiContent': {
|
"&.notistack-MuiContent": {
|
||||||
maxWidth: '50vw',
|
maxWidth: "50vw",
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import { render } from 'react-dom';
|
import { render } from "react-dom";
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from "react-redux";
|
||||||
import { store } from './store/storeRenderer';
|
import { store } from "./store/storeRenderer";
|
||||||
import { setRegistryProviders } from 'store/features/providersSlice';
|
import { setRegistryProviders } from "store/features/providersSlice";
|
||||||
import { setAlerts } from 'store/features/alertsSlice';
|
import { setAlerts } from "store/features/alertsSlice";
|
||||||
import { setXmrPrice, setBtcPrice } from 'store/features/ratesSlice';
|
import { setXmrPrice, setBtcPrice } from "store/features/ratesSlice";
|
||||||
import {
|
import {
|
||||||
fetchAlertsViaHttp,
|
fetchAlertsViaHttp,
|
||||||
fetchBtcPrice,
|
fetchBtcPrice,
|
||||||
fetchProvidersViaHttp,
|
fetchProvidersViaHttp,
|
||||||
fetchXmrPrice,
|
fetchXmrPrice,
|
||||||
} from './api';
|
} from "./api";
|
||||||
import logger from '../utils/logger';
|
import logger from "../utils/logger";
|
||||||
import App from './components/App';
|
import App from "./components/App";
|
||||||
import { checkBitcoinBalance, getRawSwapInfos } from './rpc';
|
import { checkBitcoinBalance, getRawSwapInfos } from "./rpc";
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
checkBitcoinBalance();
|
checkBitcoinBalance();
|
||||||
|
@ -23,7 +23,7 @@ render(
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<App />
|
<App />
|
||||||
</Provider>,
|
</Provider>,
|
||||||
document.getElementById('root'),
|
document.getElementById("root"),
|
||||||
);
|
);
|
||||||
|
|
||||||
async function fetchInitialData() {
|
async function fetchInitialData() {
|
||||||
|
@ -33,30 +33,30 @@ async function fetchInitialData() {
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
{ providerList },
|
{ providerList },
|
||||||
'Fetched providers via UnstoppableSwap HTTP API',
|
"Fetched providers via UnstoppableSwap HTTP API",
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(e, 'Failed to fetch providers via UnstoppableSwap HTTP API');
|
logger.error(e, "Failed to fetch providers via UnstoppableSwap HTTP API");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const alerts = await fetchAlertsViaHttp();
|
const alerts = await fetchAlertsViaHttp();
|
||||||
store.dispatch(setAlerts(alerts));
|
store.dispatch(setAlerts(alerts));
|
||||||
logger.info({ alerts }, 'Fetched alerts via UnstoppableSwap HTTP API');
|
logger.info({ alerts }, "Fetched alerts via UnstoppableSwap HTTP API");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(e, 'Failed to fetch alerts via UnstoppableSwap HTTP API');
|
logger.error(e, "Failed to fetch alerts via UnstoppableSwap HTTP API");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const xmrPrice = await fetchXmrPrice();
|
const xmrPrice = await fetchXmrPrice();
|
||||||
store.dispatch(setXmrPrice(xmrPrice));
|
store.dispatch(setXmrPrice(xmrPrice));
|
||||||
logger.info({ xmrPrice }, 'Fetched XMR price');
|
logger.info({ xmrPrice }, "Fetched XMR price");
|
||||||
|
|
||||||
const btcPrice = await fetchBtcPrice();
|
const btcPrice = await fetchBtcPrice();
|
||||||
store.dispatch(setBtcPrice(btcPrice));
|
store.dispatch(setBtcPrice(btcPrice));
|
||||||
logger.info({ btcPrice }, 'Fetched BTC price');
|
logger.info({ btcPrice }, "Fetched BTC price");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(e, 'Error retrieving fiat prices');
|
logger.error(e, "Error retrieving fiat prices");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { configureStore } from '@reduxjs/toolkit';
|
import { configureStore } from "@reduxjs/toolkit";
|
||||||
import { reducers } from 'store/combinedReducer';
|
import { reducers } from "store/combinedReducer";
|
||||||
|
|
||||||
export const store = configureStore({
|
export const store = configureStore({
|
||||||
reducer: reducers,
|
reducer: reducers,
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import swapReducer from './features/swapSlice';
|
import swapReducer from "./features/swapSlice";
|
||||||
import providersSlice from './features/providersSlice';
|
import providersSlice from "./features/providersSlice";
|
||||||
import torSlice from './features/torSlice';
|
import torSlice from "./features/torSlice";
|
||||||
import rpcSlice from './features/rpcSlice';
|
import rpcSlice from "./features/rpcSlice";
|
||||||
import alertsSlice from './features/alertsSlice';
|
import alertsSlice from "./features/alertsSlice";
|
||||||
import ratesSlice from './features/ratesSlice';
|
import ratesSlice from "./features/ratesSlice";
|
||||||
|
|
||||||
export const reducers = {
|
export const reducers = {
|
||||||
swap: swapReducer,
|
swap: swapReducer,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||||
import { Alert } from 'models/apiModel';
|
import { Alert } from "models/apiModel";
|
||||||
|
|
||||||
export interface AlertsSlice {
|
export interface AlertsSlice {
|
||||||
alerts: Alert[];
|
alerts: Alert[];
|
||||||
|
@ -10,7 +10,7 @@ const initialState: AlertsSlice = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const alertsSlice = createSlice({
|
const alertsSlice = createSlice({
|
||||||
name: 'alerts',
|
name: "alerts",
|
||||||
initialState,
|
initialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
setAlerts(slice, action: PayloadAction<Alert[]>) {
|
setAlerts(slice, action: PayloadAction<Alert[]>) {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||||
import { ExtendedProviderStatus, ProviderStatus } from 'models/apiModel';
|
import { ExtendedProviderStatus, ProviderStatus } from "models/apiModel";
|
||||||
import { sortProviderList } from 'utils/sortUtils';
|
import { sortProviderList } from "utils/sortUtils";
|
||||||
import { isProviderCompatible } from 'utils/multiAddrUtils';
|
import { isProviderCompatible } from "utils/multiAddrUtils";
|
||||||
import { getStubTestnetProvider } from 'store/config';
|
import { getStubTestnetProvider } from "store/config";
|
||||||
|
|
||||||
const stubTestnetProvider = getStubTestnetProvider();
|
const stubTestnetProvider = getStubTestnetProvider();
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ function selectNewSelectedProvider(
|
||||||
}
|
}
|
||||||
|
|
||||||
export const providersSlice = createSlice({
|
export const providersSlice = createSlice({
|
||||||
name: 'providers',
|
name: "providers",
|
||||||
initialState,
|
initialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
discoveredProvidersByRendezvous(
|
discoveredProvidersByRendezvous(
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue