mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2025-08-18 11:08:08 -04:00
feat: cargo project at root
This commit is contained in:
parent
aa0c0623ca
commit
709a2820c4
313 changed files with 1 additions and 740 deletions
28
src-gui/src/models/apiModel.ts
Normal file
28
src-gui/src/models/apiModel.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
export interface ExtendedProviderStatus extends ProviderStatus {
|
||||
uptime?: number;
|
||||
age?: number;
|
||||
relevancy?: number;
|
||||
version?: string;
|
||||
recommended?: boolean;
|
||||
}
|
||||
|
||||
export interface ProviderStatus extends ProviderQuote, Provider {}
|
||||
|
||||
export interface ProviderQuote {
|
||||
price: number;
|
||||
minSwapAmount: number;
|
||||
maxSwapAmount: number;
|
||||
}
|
||||
|
||||
export interface Provider {
|
||||
multiAddr: string;
|
||||
testnet: boolean;
|
||||
peerId: string;
|
||||
}
|
||||
|
||||
export interface Alert {
|
||||
id: number;
|
||||
title: string;
|
||||
body: string;
|
||||
severity: 'info' | 'warning' | 'error';
|
||||
}
|
406
src-gui/src/models/cliModel.ts
Normal file
406
src-gui/src/models/cliModel.ts
Normal file
|
@ -0,0 +1,406 @@
|
|||
export enum SwapSpawnType {
|
||||
INIT = 'init',
|
||||
RESUME = 'resume',
|
||||
CANCEL_REFUND = 'cancel-refund',
|
||||
}
|
||||
|
||||
export type CliLogSpanType = string | 'BitcoinWalletSubscription';
|
||||
|
||||
export interface CliLog {
|
||||
timestamp: string;
|
||||
level: 'DEBUG' | 'INFO' | 'WARN' | 'ERROR' | 'TRACE';
|
||||
fields: {
|
||||
message: string;
|
||||
[index: string]: unknown;
|
||||
};
|
||||
spans?: {
|
||||
name: CliLogSpanType;
|
||||
[index: string]: unknown;
|
||||
}[];
|
||||
}
|
||||
|
||||
export function isCliLog(log: unknown): log is CliLog {
|
||||
if (log && typeof log === 'object') {
|
||||
return (
|
||||
'timestamp' in (log as CliLog) &&
|
||||
'level' in (log as CliLog) &&
|
||||
'fields' in (log as CliLog) &&
|
||||
typeof (log as CliLog).fields?.message === 'string'
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export interface CliLogStartedRpcServer extends CliLog {
|
||||
fields: {
|
||||
message: 'Started RPC server';
|
||||
addr: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function isCliLogStartedRpcServer(
|
||||
log: CliLog,
|
||||
): log is CliLogStartedRpcServer {
|
||||
return log.fields.message === 'Started RPC server';
|
||||
}
|
||||
|
||||
export interface CliLogReleasingSwapLockLog extends CliLog {
|
||||
fields: {
|
||||
message: 'Releasing swap lock';
|
||||
swap_id: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function isCliLogReleasingSwapLockLog(
|
||||
log: CliLog,
|
||||
): log is CliLogReleasingSwapLockLog {
|
||||
return log.fields.message === 'Releasing swap lock';
|
||||
}
|
||||
|
||||
export interface CliLogApiCallError extends CliLog {
|
||||
fields: {
|
||||
message: 'API call resulted in an error';
|
||||
err: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function isCliLogApiCallError(log: CliLog): log is CliLogApiCallError {
|
||||
return log.fields.message === 'API call resulted in an error';
|
||||
}
|
||||
|
||||
export interface CliLogAcquiringSwapLockLog extends CliLog {
|
||||
fields: {
|
||||
message: 'Acquiring swap lock';
|
||||
swap_id: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function isCliLogAcquiringSwapLockLog(
|
||||
log: CliLog,
|
||||
): log is CliLogAcquiringSwapLockLog {
|
||||
return log.fields.message === 'Acquiring swap lock';
|
||||
}
|
||||
|
||||
export interface CliLogReceivedQuote extends CliLog {
|
||||
fields: {
|
||||
message: 'Received quote';
|
||||
price: string;
|
||||
minimum_amount: string;
|
||||
maximum_amount: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function isCliLogReceivedQuote(log: CliLog): log is CliLogReceivedQuote {
|
||||
return log.fields.message === 'Received quote';
|
||||
}
|
||||
|
||||
export interface CliLogWaitingForBtcDeposit extends CliLog {
|
||||
fields: {
|
||||
message: 'Waiting for Bitcoin deposit';
|
||||
deposit_address: string;
|
||||
min_deposit_until_swap_will_start: string;
|
||||
max_deposit_until_maximum_amount_is_reached: string;
|
||||
max_giveable: string;
|
||||
minimum_amount: string;
|
||||
maximum_amount: string;
|
||||
min_bitcoin_lock_tx_fee: string;
|
||||
price: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function isCliLogWaitingForBtcDeposit(
|
||||
log: CliLog,
|
||||
): log is CliLogWaitingForBtcDeposit {
|
||||
return log.fields.message === 'Waiting for Bitcoin deposit';
|
||||
}
|
||||
|
||||
export interface CliLogReceivedBtc extends CliLog {
|
||||
fields: {
|
||||
message: 'Received Bitcoin';
|
||||
max_giveable: string;
|
||||
new_balance: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function isCliLogReceivedBtc(log: CliLog): log is CliLogReceivedBtc {
|
||||
return log.fields.message === 'Received Bitcoin';
|
||||
}
|
||||
|
||||
export interface CliLogDeterminedSwapAmount extends CliLog {
|
||||
fields: {
|
||||
message: 'Determined swap amount';
|
||||
amount: string;
|
||||
fees: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function isCliLogDeterminedSwapAmount(
|
||||
log: CliLog,
|
||||
): log is CliLogDeterminedSwapAmount {
|
||||
return log.fields.message === 'Determined swap amount';
|
||||
}
|
||||
|
||||
export interface CliLogStartedSwap extends CliLog {
|
||||
fields: {
|
||||
message: 'Starting new swap';
|
||||
swap_id: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function isCliLogStartedSwap(log: CliLog): log is CliLogStartedSwap {
|
||||
return log.fields.message === 'Starting new swap';
|
||||
}
|
||||
|
||||
export interface CliLogPublishedBtcTx extends CliLog {
|
||||
fields: {
|
||||
message: 'Published Bitcoin transaction';
|
||||
txid: string;
|
||||
kind: 'lock' | 'cancel' | 'withdraw' | 'refund';
|
||||
};
|
||||
}
|
||||
|
||||
export function isCliLogPublishedBtcTx(
|
||||
log: CliLog,
|
||||
): log is CliLogPublishedBtcTx {
|
||||
return log.fields.message === 'Published Bitcoin transaction';
|
||||
}
|
||||
|
||||
export interface CliLogBtcTxFound extends CliLog {
|
||||
fields: {
|
||||
message: 'Found relevant Bitcoin transaction';
|
||||
txid: string;
|
||||
status: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function isCliLogBtcTxFound(log: CliLog): log is CliLogBtcTxFound {
|
||||
return log.fields.message === 'Found relevant Bitcoin transaction';
|
||||
}
|
||||
|
||||
export interface CliLogBtcTxStatusChanged extends CliLog {
|
||||
fields: {
|
||||
message: 'Bitcoin transaction status changed';
|
||||
txid: string;
|
||||
new_status: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function isCliLogBtcTxStatusChanged(
|
||||
log: CliLog,
|
||||
): log is CliLogBtcTxStatusChanged {
|
||||
return log.fields.message === 'Bitcoin transaction status changed';
|
||||
}
|
||||
|
||||
export interface CliLogAliceLockedXmr extends CliLog {
|
||||
fields: {
|
||||
message: 'Alice locked Monero';
|
||||
txid: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function isCliLogAliceLockedXmr(
|
||||
log: CliLog,
|
||||
): log is CliLogAliceLockedXmr {
|
||||
return log.fields.message === 'Alice locked Monero';
|
||||
}
|
||||
|
||||
export interface CliLogReceivedXmrLockTxConfirmation extends CliLog {
|
||||
fields: {
|
||||
message: 'Received new confirmation for Monero lock tx';
|
||||
txid: string;
|
||||
seen_confirmations: string;
|
||||
needed_confirmations: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function isCliLogReceivedXmrLockTxConfirmation(
|
||||
log: CliLog,
|
||||
): log is CliLogReceivedXmrLockTxConfirmation {
|
||||
return log.fields.message === 'Received new confirmation for Monero lock tx';
|
||||
}
|
||||
|
||||
export interface CliLogAdvancingState extends CliLog {
|
||||
fields: {
|
||||
message: 'Advancing state';
|
||||
state:
|
||||
| 'quote has been requested'
|
||||
| 'execution setup done'
|
||||
| 'btc is locked'
|
||||
| 'XMR lock transaction transfer proof received'
|
||||
| 'xmr is locked'
|
||||
| 'encrypted signature is sent'
|
||||
| 'btc is redeemed'
|
||||
| 'cancel timelock is expired'
|
||||
| 'btc is cancelled'
|
||||
| 'btc is refunded'
|
||||
| 'xmr is redeemed'
|
||||
| 'btc is punished'
|
||||
| 'safely aborted';
|
||||
};
|
||||
}
|
||||
|
||||
export function isCliLogAdvancingState(
|
||||
log: CliLog,
|
||||
): log is CliLogAdvancingState {
|
||||
return log.fields.message === 'Advancing state';
|
||||
}
|
||||
|
||||
export interface CliLogRedeemedXmr extends CliLog {
|
||||
fields: {
|
||||
message: 'Successfully transferred XMR to wallet';
|
||||
monero_receive_address: string;
|
||||
txid: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function isCliLogRedeemedXmr(log: CliLog): log is CliLogRedeemedXmr {
|
||||
return log.fields.message === 'Successfully transferred XMR to wallet';
|
||||
}
|
||||
|
||||
export interface YouHaveBeenPunishedCliLog extends CliLog {
|
||||
fields: {
|
||||
message: 'You have been punished for not refunding in time';
|
||||
};
|
||||
}
|
||||
|
||||
export function isYouHaveBeenPunishedCliLog(
|
||||
log: CliLog,
|
||||
): log is YouHaveBeenPunishedCliLog {
|
||||
return (
|
||||
log.fields.message === 'You have been punished for not refunding in time'
|
||||
);
|
||||
}
|
||||
|
||||
function getCliLogSpanAttribute<T>(log: CliLog, key: string): T | null {
|
||||
const span = log.spans?.find((s) => s[key]);
|
||||
if (!span) {
|
||||
return null;
|
||||
}
|
||||
return span[key] as T;
|
||||
}
|
||||
|
||||
export function getCliLogSpanSwapId(log: CliLog): string | null {
|
||||
return getCliLogSpanAttribute<string>(log, 'swap_id');
|
||||
}
|
||||
|
||||
export function getCliLogSpanLogReferenceId(log: CliLog): string | null {
|
||||
return (
|
||||
getCliLogSpanAttribute<string>(log, 'log_reference_id')?.replace(
|
||||
/"/g,
|
||||
'',
|
||||
) || null
|
||||
);
|
||||
}
|
||||
|
||||
export function hasCliLogOneOfMultipleSpans(
|
||||
log: CliLog,
|
||||
spanNames: string[],
|
||||
): boolean {
|
||||
return log.spans?.some((s) => spanNames.includes(s.name)) ?? false;
|
||||
}
|
||||
|
||||
export interface CliLogStartedSyncingMoneroWallet extends CliLog {
|
||||
fields: {
|
||||
message: 'Syncing Monero wallet';
|
||||
current_sync_height?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export function isCliLogStartedSyncingMoneroWallet(
|
||||
log: CliLog,
|
||||
): log is CliLogStartedSyncingMoneroWallet {
|
||||
return log.fields.message === 'Syncing Monero wallet';
|
||||
}
|
||||
|
||||
export interface CliLogFinishedSyncingMoneroWallet extends CliLog {
|
||||
fields: {
|
||||
message: 'Synced Monero wallet';
|
||||
};
|
||||
}
|
||||
|
||||
export interface CliLogFailedToSyncMoneroWallet extends CliLog {
|
||||
fields: {
|
||||
message: 'Failed to sync Monero wallet';
|
||||
error: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function isCliLogFailedToSyncMoneroWallet(
|
||||
log: CliLog,
|
||||
): log is CliLogFailedToSyncMoneroWallet {
|
||||
return log.fields.message === 'Failed to sync Monero wallet';
|
||||
}
|
||||
|
||||
export function isCliLogFinishedSyncingMoneroWallet(
|
||||
log: CliLog,
|
||||
): log is CliLogFinishedSyncingMoneroWallet {
|
||||
return log.fields.message === 'Monero wallet synced';
|
||||
}
|
||||
|
||||
export interface CliLogDownloadingMoneroWalletRpc extends CliLog {
|
||||
fields: {
|
||||
message: 'Downloading monero-wallet-rpc';
|
||||
progress: string;
|
||||
size: string;
|
||||
download_url: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function isCliLogDownloadingMoneroWalletRpc(
|
||||
log: CliLog,
|
||||
): log is CliLogDownloadingMoneroWalletRpc {
|
||||
return log.fields.message === 'Downloading monero-wallet-rpc';
|
||||
}
|
||||
|
||||
export interface CliLogStartedSyncingMoneroWallet extends CliLog {
|
||||
fields: {
|
||||
message: 'Syncing Monero wallet';
|
||||
current_sync_height?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface CliLogDownloadingMoneroWalletRpc extends CliLog {
|
||||
fields: {
|
||||
message: 'Downloading monero-wallet-rpc';
|
||||
progress: string;
|
||||
size: string;
|
||||
download_url: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface CliLogGotNotificationForNewBlock extends CliLog {
|
||||
fields: {
|
||||
message: 'Got notification for new block';
|
||||
block_height: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function isCliLogGotNotificationForNewBlock(
|
||||
log: CliLog,
|
||||
): log is CliLogGotNotificationForNewBlock {
|
||||
return log.fields.message === 'Got notification for new block';
|
||||
}
|
||||
|
||||
export interface CliLogAttemptingToCooperativelyRedeemXmr extends CliLog {
|
||||
fields: {
|
||||
message: 'Attempting to cooperatively redeem XMR after being punished';
|
||||
};
|
||||
}
|
||||
|
||||
export function isCliLogAttemptingToCooperativelyRedeemXmr(
|
||||
log: CliLog,
|
||||
): log is CliLogAttemptingToCooperativelyRedeemXmr {
|
||||
return log.fields.message === 'Attempting to cooperatively redeem XMR after being punished';
|
||||
}
|
||||
|
||||
export interface CliLogAliceHasAcceptedOurRequestToCooperativelyRedeemTheXmr extends CliLog {
|
||||
fields: {
|
||||
message: 'Alice has accepted our request to cooperatively redeem the XMR';
|
||||
};
|
||||
}
|
||||
|
||||
export function isCliLogAliceHasAcceptedOurRequestToCooperativelyRedeemTheXmr(
|
||||
log: CliLog,
|
||||
): log is CliLogAliceHasAcceptedOurRequestToCooperativelyRedeemTheXmr {
|
||||
return log.fields.message === 'Alice has accepted our request to cooperatively redeem the XMR';
|
||||
}
|
4
src-gui/src/models/downloaderModel.ts
Normal file
4
src-gui/src/models/downloaderModel.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export interface Binary {
|
||||
dirPath: string; // Path without filename appended
|
||||
fileName: string;
|
||||
}
|
336
src-gui/src/models/rpcModel.ts
Normal file
336
src-gui/src/models/rpcModel.ts
Normal file
|
@ -0,0 +1,336 @@
|
|||
import { piconerosToXmr, satsToBtc } from 'utils/conversionUtils';
|
||||
import { exhaustiveGuard } from 'utils/typescriptUtils';
|
||||
|
||||
export enum RpcMethod {
|
||||
GET_BTC_BALANCE = 'get_bitcoin_balance',
|
||||
WITHDRAW_BTC = 'withdraw_btc',
|
||||
BUY_XMR = 'buy_xmr',
|
||||
RESUME_SWAP = 'resume_swap',
|
||||
LIST_SELLERS = 'list_sellers',
|
||||
CANCEL_REFUND_SWAP = 'cancel_refund_swap',
|
||||
GET_SWAP_INFO = 'get_swap_info',
|
||||
SUSPEND_CURRENT_SWAP = 'suspend_current_swap',
|
||||
GET_HISTORY = 'get_history',
|
||||
GET_MONERO_RECOVERY_KEYS = 'get_monero_recovery_info',
|
||||
}
|
||||
|
||||
export enum RpcProcessStateType {
|
||||
STARTED = 'starting...',
|
||||
LISTENING_FOR_CONNECTIONS = 'running',
|
||||
EXITED = 'exited',
|
||||
NOT_STARTED = 'not started',
|
||||
}
|
||||
|
||||
export type RawRpcResponseSuccess<T> = {
|
||||
jsonrpc: string;
|
||||
id: string;
|
||||
result: T;
|
||||
};
|
||||
|
||||
export type RawRpcResponseError = {
|
||||
jsonrpc: string;
|
||||
id: string;
|
||||
error: { code: number; message: string };
|
||||
};
|
||||
|
||||
export type RawRpcResponse<T> = RawRpcResponseSuccess<T> | RawRpcResponseError;
|
||||
|
||||
export function isSuccessResponse<T>(
|
||||
response: RawRpcResponse<T>,
|
||||
): response is RawRpcResponseSuccess<T> {
|
||||
return 'result' in response;
|
||||
}
|
||||
|
||||
export function isErrorResponse<T>(
|
||||
response: RawRpcResponse<T>,
|
||||
): response is RawRpcResponseError {
|
||||
return 'error' in response;
|
||||
}
|
||||
|
||||
export interface RpcSellerStatus {
|
||||
status:
|
||||
| {
|
||||
Online: {
|
||||
price: number;
|
||||
min_quantity: number;
|
||||
max_quantity: number;
|
||||
};
|
||||
}
|
||||
| 'Unreachable';
|
||||
multiaddr: string;
|
||||
}
|
||||
|
||||
export interface WithdrawBitcoinResponse {
|
||||
txid: string;
|
||||
}
|
||||
|
||||
export interface BuyXmrResponse {
|
||||
swapId: string;
|
||||
}
|
||||
|
||||
export type SwapTimelockInfoNone = {
|
||||
None: {
|
||||
blocks_left: number;
|
||||
};
|
||||
};
|
||||
|
||||
export type SwapTimelockInfoCancelled = {
|
||||
Cancel: {
|
||||
blocks_left: number;
|
||||
};
|
||||
};
|
||||
|
||||
export type SwapTimelockInfoPunished = 'Punish';
|
||||
|
||||
export type SwapTimelockInfo =
|
||||
| SwapTimelockInfoNone
|
||||
| SwapTimelockInfoCancelled
|
||||
| SwapTimelockInfoPunished;
|
||||
|
||||
export function isSwapTimelockInfoNone(
|
||||
info: SwapTimelockInfo,
|
||||
): info is SwapTimelockInfoNone {
|
||||
return typeof info === 'object' && 'None' in info;
|
||||
}
|
||||
|
||||
export function isSwapTimelockInfoCancelled(
|
||||
info: SwapTimelockInfo,
|
||||
): info is SwapTimelockInfoCancelled {
|
||||
return typeof info === 'object' && 'Cancel' in info;
|
||||
}
|
||||
|
||||
export function isSwapTimelockInfoPunished(
|
||||
info: SwapTimelockInfo,
|
||||
): info is SwapTimelockInfoPunished {
|
||||
return info === 'Punish';
|
||||
}
|
||||
|
||||
export type SwapSellerInfo = {
|
||||
peerId: string;
|
||||
addresses: string[];
|
||||
};
|
||||
|
||||
export interface GetSwapInfoResponse {
|
||||
swapId: string;
|
||||
completed: boolean;
|
||||
seller: SwapSellerInfo;
|
||||
startDate: string;
|
||||
stateName: SwapStateName;
|
||||
timelock: null | SwapTimelockInfo;
|
||||
txLockId: string;
|
||||
txCancelFee: number;
|
||||
txRefundFee: number;
|
||||
txLockFee: number;
|
||||
btcAmount: number;
|
||||
xmrAmount: number;
|
||||
btcRefundAddress: string;
|
||||
cancelTimelock: number;
|
||||
punishTimelock: number;
|
||||
}
|
||||
|
||||
export type MoneroRecoveryResponse = {
|
||||
address: string;
|
||||
spend_key: string;
|
||||
view_key: string;
|
||||
restore_height: number;
|
||||
};
|
||||
|
||||
export interface BalanceBitcoinResponse {
|
||||
balance: number;
|
||||
}
|
||||
|
||||
export interface GetHistoryResponse {
|
||||
swaps: [swapId: string, stateName: SwapStateName][];
|
||||
}
|
||||
|
||||
export enum SwapStateName {
|
||||
Started = 'quote has been requested',
|
||||
SwapSetupCompleted = 'execution setup done',
|
||||
BtcLocked = 'btc is locked',
|
||||
XmrLockProofReceived = 'XMR lock transaction transfer proof received',
|
||||
XmrLocked = 'xmr is locked',
|
||||
EncSigSent = 'encrypted signature is sent',
|
||||
BtcRedeemed = 'btc is redeemed',
|
||||
CancelTimelockExpired = 'cancel timelock is expired',
|
||||
BtcCancelled = 'btc is cancelled',
|
||||
BtcRefunded = 'btc is refunded',
|
||||
XmrRedeemed = 'xmr is redeemed',
|
||||
BtcPunished = 'btc is punished',
|
||||
SafelyAborted = 'safely aborted',
|
||||
}
|
||||
|
||||
export type SwapStateNameRunningSwap = Exclude<
|
||||
SwapStateName,
|
||||
| SwapStateName.Started
|
||||
| SwapStateName.SwapSetupCompleted
|
||||
| SwapStateName.BtcRefunded
|
||||
| SwapStateName.BtcPunished
|
||||
| SwapStateName.SafelyAborted
|
||||
| SwapStateName.XmrRedeemed
|
||||
>;
|
||||
|
||||
export type GetSwapInfoResponseRunningSwap = GetSwapInfoResponse & {
|
||||
stateName: SwapStateNameRunningSwap;
|
||||
};
|
||||
|
||||
export function isSwapStateNameRunningSwap(
|
||||
state: SwapStateName,
|
||||
): state is SwapStateNameRunningSwap {
|
||||
return ![
|
||||
SwapStateName.Started,
|
||||
SwapStateName.SwapSetupCompleted,
|
||||
SwapStateName.BtcRefunded,
|
||||
SwapStateName.BtcPunished,
|
||||
SwapStateName.SafelyAborted,
|
||||
SwapStateName.XmrRedeemed,
|
||||
].includes(state);
|
||||
}
|
||||
|
||||
export type SwapStateNameCompletedSwap =
|
||||
| SwapStateName.XmrRedeemed
|
||||
| SwapStateName.BtcRefunded
|
||||
| SwapStateName.BtcPunished
|
||||
| SwapStateName.SafelyAborted;
|
||||
|
||||
export function isSwapStateNameCompletedSwap(
|
||||
state: SwapStateName,
|
||||
): state is SwapStateNameCompletedSwap {
|
||||
return [
|
||||
SwapStateName.XmrRedeemed,
|
||||
SwapStateName.BtcRefunded,
|
||||
SwapStateName.BtcPunished,
|
||||
SwapStateName.SafelyAborted,
|
||||
].includes(state);
|
||||
}
|
||||
|
||||
export type SwapStateNamePossiblyCancellableSwap =
|
||||
| SwapStateName.BtcLocked
|
||||
| SwapStateName.XmrLockProofReceived
|
||||
| SwapStateName.XmrLocked
|
||||
| SwapStateName.EncSigSent
|
||||
| SwapStateName.CancelTimelockExpired;
|
||||
|
||||
/**
|
||||
Checks if a swap is in a state where it can possibly be cancelled
|
||||
|
||||
The following conditions must be met:
|
||||
- The bitcoin must be locked
|
||||
- The bitcoin must not be redeemed
|
||||
- The bitcoin must not be cancelled
|
||||
- The bitcoin must not be refunded
|
||||
- The bitcoin must not be punished
|
||||
|
||||
See: https://github.com/comit-network/xmr-btc-swap/blob/7023e75bb51ab26dff4c8fcccdc855d781ca4b15/swap/src/cli/cancel.rs#L16-L35
|
||||
*/
|
||||
export function isSwapStateNamePossiblyCancellableSwap(
|
||||
state: SwapStateName,
|
||||
): state is SwapStateNamePossiblyCancellableSwap {
|
||||
return [
|
||||
SwapStateName.BtcLocked,
|
||||
SwapStateName.XmrLockProofReceived,
|
||||
SwapStateName.XmrLocked,
|
||||
SwapStateName.EncSigSent,
|
||||
SwapStateName.CancelTimelockExpired,
|
||||
].includes(state);
|
||||
}
|
||||
|
||||
export type SwapStateNamePossiblyRefundableSwap =
|
||||
| SwapStateName.BtcLocked
|
||||
| SwapStateName.XmrLockProofReceived
|
||||
| SwapStateName.XmrLocked
|
||||
| SwapStateName.EncSigSent
|
||||
| SwapStateName.CancelTimelockExpired
|
||||
| SwapStateName.BtcCancelled;
|
||||
|
||||
/**
|
||||
Checks if a swap is in a state where it can possibly be refunded (meaning it's not impossible)
|
||||
|
||||
The following conditions must be met:
|
||||
- The bitcoin must be locked
|
||||
- The bitcoin must not be redeemed
|
||||
- The bitcoin must not be refunded
|
||||
- The bitcoin must not be punished
|
||||
|
||||
See: https://github.com/comit-network/xmr-btc-swap/blob/7023e75bb51ab26dff4c8fcccdc855d781ca4b15/swap/src/cli/refund.rs#L16-L34
|
||||
*/
|
||||
export function isSwapStateNamePossiblyRefundableSwap(
|
||||
state: SwapStateName,
|
||||
): state is SwapStateNamePossiblyRefundableSwap {
|
||||
return [
|
||||
SwapStateName.BtcLocked,
|
||||
SwapStateName.XmrLockProofReceived,
|
||||
SwapStateName.XmrLocked,
|
||||
SwapStateName.EncSigSent,
|
||||
SwapStateName.CancelTimelockExpired,
|
||||
SwapStateName.BtcCancelled,
|
||||
].includes(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Type guard for GetSwapInfoResponseRunningSwap
|
||||
* "running" means the swap is in progress and not yet completed
|
||||
* If a swap is not "running" it means it is either completed or no Bitcoin have been locked yet
|
||||
* @param response
|
||||
*/
|
||||
export function isGetSwapInfoResponseRunningSwap(
|
||||
response: GetSwapInfoResponse,
|
||||
): response is GetSwapInfoResponseRunningSwap {
|
||||
return isSwapStateNameRunningSwap(response.stateName);
|
||||
}
|
||||
|
||||
export function isSwapMoneroRecoverable(swapStateName: SwapStateName): boolean {
|
||||
return [SwapStateName.BtcRedeemed].includes(swapStateName);
|
||||
}
|
||||
|
||||
// See https://github.com/comit-network/xmr-btc-swap/blob/50ae54141255e03dba3d2b09036b1caa4a63e5a3/swap/src/protocol/bob/state.rs#L55
|
||||
export function getHumanReadableDbStateType(type: SwapStateName): string {
|
||||
switch (type) {
|
||||
case SwapStateName.Started:
|
||||
return 'Quote has been requested';
|
||||
case SwapStateName.SwapSetupCompleted:
|
||||
return 'Swap has been initiated';
|
||||
case SwapStateName.BtcLocked:
|
||||
return 'Bitcoin has been locked';
|
||||
case SwapStateName.XmrLockProofReceived:
|
||||
return 'Monero lock transaction transfer proof has been received';
|
||||
case SwapStateName.XmrLocked:
|
||||
return 'Monero has been locked';
|
||||
case SwapStateName.EncSigSent:
|
||||
return 'Encrypted signature has been sent';
|
||||
case SwapStateName.BtcRedeemed:
|
||||
return 'Bitcoin has been redeemed';
|
||||
case SwapStateName.CancelTimelockExpired:
|
||||
return 'Cancel timelock has expired';
|
||||
case SwapStateName.BtcCancelled:
|
||||
return 'Swap has been cancelled';
|
||||
case SwapStateName.BtcRefunded:
|
||||
return 'Bitcoin has been refunded';
|
||||
case SwapStateName.XmrRedeemed:
|
||||
return 'Monero has been redeemed';
|
||||
case SwapStateName.BtcPunished:
|
||||
return 'Bitcoin has been punished';
|
||||
case SwapStateName.SafelyAborted:
|
||||
return 'Swap has been safely aborted';
|
||||
default:
|
||||
return exhaustiveGuard(type);
|
||||
}
|
||||
}
|
||||
|
||||
export function getSwapTxFees(swap: GetSwapInfoResponse): number {
|
||||
return satsToBtc(swap.txLockFee);
|
||||
}
|
||||
|
||||
export function getSwapBtcAmount(swap: GetSwapInfoResponse): number {
|
||||
return satsToBtc(swap.btcAmount);
|
||||
}
|
||||
|
||||
export function getSwapXmrAmount(swap: GetSwapInfoResponse): number {
|
||||
return piconerosToXmr(swap.xmrAmount);
|
||||
}
|
||||
|
||||
export function getSwapExchangeRate(swap: GetSwapInfoResponse): number {
|
||||
const btcAmount = getSwapBtcAmount(swap);
|
||||
const xmrAmount = getSwapXmrAmount(swap);
|
||||
|
||||
return btcAmount / xmrAmount;
|
||||
}
|
218
src-gui/src/models/storeModel.ts
Normal file
218
src-gui/src/models/storeModel.ts
Normal file
|
@ -0,0 +1,218 @@
|
|||
import { CliLog, SwapSpawnType } from './cliModel';
|
||||
import { Provider } from './apiModel';
|
||||
|
||||
export interface SwapSlice {
|
||||
state: SwapState | null;
|
||||
logs: CliLog[];
|
||||
processRunning: boolean;
|
||||
provider: Provider | null;
|
||||
spawnType: SwapSpawnType | null;
|
||||
swapId: string | null;
|
||||
}
|
||||
|
||||
export type MoneroWalletRpcUpdateState = {
|
||||
progress: string;
|
||||
downloadUrl: string;
|
||||
};
|
||||
|
||||
export interface SwapState {
|
||||
type: SwapStateType;
|
||||
}
|
||||
|
||||
export enum SwapStateType {
|
||||
INITIATED = 'initiated',
|
||||
RECEIVED_QUOTE = 'received quote',
|
||||
WAITING_FOR_BTC_DEPOSIT = 'waiting for btc deposit',
|
||||
STARTED = 'started',
|
||||
BTC_LOCK_TX_IN_MEMPOOL = 'btc lock tx is in mempool',
|
||||
XMR_LOCK_TX_IN_MEMPOOL = 'xmr lock tx is in mempool',
|
||||
XMR_LOCKED = 'xmr is locked',
|
||||
BTC_REDEEMED = 'btc redeemed',
|
||||
XMR_REDEEM_IN_MEMPOOL = 'xmr redeem tx is in mempool',
|
||||
PROCESS_EXITED = 'process exited',
|
||||
BTC_CANCELLED = 'btc cancelled',
|
||||
BTC_REFUNDED = 'btc refunded',
|
||||
BTC_PUNISHED = 'btc punished',
|
||||
ATTEMPTING_COOPERATIVE_REDEEM = 'attempting cooperative redeem',
|
||||
COOPERATIVE_REDEEM_REJECTED = 'cooperative redeem rejected',
|
||||
}
|
||||
|
||||
export function isSwapState(state?: SwapState | null): state is SwapState {
|
||||
return state?.type != null;
|
||||
}
|
||||
|
||||
export interface SwapStateInitiated extends SwapState {
|
||||
type: SwapStateType.INITIATED;
|
||||
}
|
||||
|
||||
export function isSwapStateInitiated(
|
||||
state?: SwapState | null,
|
||||
): state is SwapStateInitiated {
|
||||
return state?.type === SwapStateType.INITIATED;
|
||||
}
|
||||
|
||||
export interface SwapStateReceivedQuote extends SwapState {
|
||||
type: SwapStateType.RECEIVED_QUOTE;
|
||||
price: number;
|
||||
minimumSwapAmount: number;
|
||||
maximumSwapAmount: number;
|
||||
}
|
||||
|
||||
export function isSwapStateReceivedQuote(
|
||||
state?: SwapState | null,
|
||||
): state is SwapStateReceivedQuote {
|
||||
return state?.type === SwapStateType.RECEIVED_QUOTE;
|
||||
}
|
||||
|
||||
export interface SwapStateWaitingForBtcDeposit extends SwapState {
|
||||
type: SwapStateType.WAITING_FOR_BTC_DEPOSIT;
|
||||
depositAddress: string;
|
||||
maxGiveable: number;
|
||||
minimumAmount: number;
|
||||
maximumAmount: number;
|
||||
minDeposit: number;
|
||||
maxDeposit: number;
|
||||
minBitcoinLockTxFee: number;
|
||||
price: number | null;
|
||||
}
|
||||
|
||||
export function isSwapStateWaitingForBtcDeposit(
|
||||
state?: SwapState | null,
|
||||
): state is SwapStateWaitingForBtcDeposit {
|
||||
return state?.type === SwapStateType.WAITING_FOR_BTC_DEPOSIT;
|
||||
}
|
||||
|
||||
export interface SwapStateStarted extends SwapState {
|
||||
type: SwapStateType.STARTED;
|
||||
txLockDetails: {
|
||||
amount: number;
|
||||
fees: number;
|
||||
} | null;
|
||||
}
|
||||
|
||||
export function isSwapStateStarted(
|
||||
state?: SwapState | null,
|
||||
): state is SwapStateStarted {
|
||||
return state?.type === SwapStateType.STARTED;
|
||||
}
|
||||
|
||||
export interface SwapStateBtcLockInMempool extends SwapState {
|
||||
type: SwapStateType.BTC_LOCK_TX_IN_MEMPOOL;
|
||||
bobBtcLockTxId: string;
|
||||
bobBtcLockTxConfirmations: number;
|
||||
}
|
||||
|
||||
export function isSwapStateBtcLockInMempool(
|
||||
state?: SwapState | null,
|
||||
): state is SwapStateBtcLockInMempool {
|
||||
return state?.type === SwapStateType.BTC_LOCK_TX_IN_MEMPOOL;
|
||||
}
|
||||
|
||||
export interface SwapStateXmrLockInMempool extends SwapState {
|
||||
type: SwapStateType.XMR_LOCK_TX_IN_MEMPOOL;
|
||||
aliceXmrLockTxId: string;
|
||||
aliceXmrLockTxConfirmations: number;
|
||||
}
|
||||
|
||||
export function isSwapStateXmrLockInMempool(
|
||||
state?: SwapState | null,
|
||||
): state is SwapStateXmrLockInMempool {
|
||||
return state?.type === SwapStateType.XMR_LOCK_TX_IN_MEMPOOL;
|
||||
}
|
||||
|
||||
export interface SwapStateXmrLocked extends SwapState {
|
||||
type: SwapStateType.XMR_LOCKED;
|
||||
}
|
||||
|
||||
export function isSwapStateXmrLocked(
|
||||
state?: SwapState | null,
|
||||
): state is SwapStateXmrLocked {
|
||||
return state?.type === SwapStateType.XMR_LOCKED;
|
||||
}
|
||||
|
||||
export interface SwapStateBtcRedemeed extends SwapState {
|
||||
type: SwapStateType.BTC_REDEEMED;
|
||||
}
|
||||
|
||||
export function isSwapStateBtcRedemeed(
|
||||
state?: SwapState | null,
|
||||
): state is SwapStateBtcRedemeed {
|
||||
return state?.type === SwapStateType.BTC_REDEEMED;
|
||||
}
|
||||
|
||||
export interface SwapStateAttemptingCooperativeRedeeem extends SwapState {
|
||||
type: SwapStateType.ATTEMPTING_COOPERATIVE_REDEEM;
|
||||
}
|
||||
|
||||
export function isSwapStateAttemptingCooperativeRedeeem(
|
||||
state?: SwapState | null,
|
||||
): state is SwapStateAttemptingCooperativeRedeeem {
|
||||
return state?.type === SwapStateType.ATTEMPTING_COOPERATIVE_REDEEM;
|
||||
}
|
||||
|
||||
export interface SwapStateCooperativeRedeemRejected extends SwapState {
|
||||
type: SwapStateType.COOPERATIVE_REDEEM_REJECTED;
|
||||
reason: string;
|
||||
}
|
||||
|
||||
export function isSwapStateCooperativeRedeemRejected(
|
||||
state?: SwapState | null,
|
||||
): state is SwapStateCooperativeRedeemRejected {
|
||||
return state?.type === SwapStateType.COOPERATIVE_REDEEM_REJECTED;
|
||||
}
|
||||
|
||||
export interface SwapStateXmrRedeemInMempool extends SwapState {
|
||||
type: SwapStateType.XMR_REDEEM_IN_MEMPOOL;
|
||||
bobXmrRedeemTxId: string;
|
||||
bobXmrRedeemAddress: string;
|
||||
}
|
||||
|
||||
export function isSwapStateXmrRedeemInMempool(
|
||||
state?: SwapState | null,
|
||||
): state is SwapStateXmrRedeemInMempool {
|
||||
return state?.type === SwapStateType.XMR_REDEEM_IN_MEMPOOL;
|
||||
}
|
||||
|
||||
export interface SwapStateBtcCancelled extends SwapState {
|
||||
type: SwapStateType.BTC_CANCELLED;
|
||||
btcCancelTxId: string;
|
||||
}
|
||||
|
||||
export function isSwapStateBtcCancelled(
|
||||
state?: SwapState | null,
|
||||
): state is SwapStateBtcCancelled {
|
||||
return state?.type === SwapStateType.BTC_CANCELLED;
|
||||
}
|
||||
|
||||
export interface SwapStateBtcRefunded extends SwapState {
|
||||
type: SwapStateType.BTC_REFUNDED;
|
||||
bobBtcRefundTxId: string;
|
||||
}
|
||||
|
||||
export function isSwapStateBtcRefunded(
|
||||
state?: SwapState | null,
|
||||
): state is SwapStateBtcRefunded {
|
||||
return state?.type === SwapStateType.BTC_REFUNDED;
|
||||
}
|
||||
|
||||
export interface SwapStateBtcPunished extends SwapState {
|
||||
type: SwapStateType.BTC_PUNISHED;
|
||||
}
|
||||
|
||||
export function isSwapStateBtcPunished(
|
||||
state?: SwapState | null,
|
||||
): state is SwapStateBtcPunished {
|
||||
return state?.type === SwapStateType.BTC_PUNISHED;
|
||||
}
|
||||
|
||||
export interface SwapStateProcessExited extends SwapState {
|
||||
type: SwapStateType.PROCESS_EXITED;
|
||||
prevState: SwapState | null;
|
||||
rpcError: string | null;
|
||||
}
|
||||
|
||||
export function isSwapStateProcessExited(
|
||||
state?: SwapState | null,
|
||||
): state is SwapStateProcessExited {
|
||||
return state?.type === SwapStateType.PROCESS_EXITED;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue