feat(gui): Display timelock status using a timeline (#153)

This commit is contained in:
binarybaron 2024-11-14 13:33:20 +01:00 committed by GitHub
parent 3e79bb3712
commit 4cf5cf719a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 499 additions and 343 deletions

View file

@ -1,3 +1,4 @@
import { exhaustiveGuard } from "utils/typescriptUtils";
import {
ExpiredTimelocks,
GetSwapInfoResponse,
@ -30,6 +31,26 @@ export enum BobStateName {
SafelyAborted = "safely aborted",
}
export function bobStateNameToHumanReadable(stateName: BobStateName): string {
switch (stateName) {
case BobStateName.Started: return "Started";
case BobStateName.SwapSetupCompleted: return "Setup completed";
case BobStateName.BtcLocked: return "Bitcoin locked";
case BobStateName.XmrLockProofReceived: return "Monero locked";
case BobStateName.XmrLocked: return "Monero locked and fully confirmed";
case BobStateName.EncSigSent: return "Encrypted signature sent";
case BobStateName.BtcRedeemed: return "Bitcoin redeemed";
case BobStateName.CancelTimelockExpired: return "Cancel timelock expired";
case BobStateName.BtcCancelled: return "Bitcoin cancelled";
case BobStateName.BtcRefunded: return "Bitcoin refunded";
case BobStateName.XmrRedeemed: return "Monero redeemed";
case BobStateName.BtcPunished: return "Bitcoin punished";
case BobStateName.SafelyAborted: return "Safely aborted";
default:
return exhaustiveGuard(stateName);
}
}
// TODO: This is a temporary solution until we have a typeshare definition for BobStateName
export type GetSwapInfoResponseExt = GetSwapInfoResponse & {
state_name: BobStateName;
@ -39,6 +60,22 @@ export type TimelockNone = Extract<ExpiredTimelocks, { type: "None" }>;
export type TimelockCancel = Extract<ExpiredTimelocks, { type: "Cancel" }>;
export type TimelockPunish = Extract<ExpiredTimelocks, { type: "Punish" }>;
// This function returns the absolute block number of the timelock relative to the block the tx_lock was included in
export function getAbsoluteBlock(timelock: ExpiredTimelocks, cancelTimelock: number, punishTimelock: number): number {
if (timelock.type === "None") {
return cancelTimelock - timelock.content.blocks_left;
}
if (timelock.type === "Cancel") {
return cancelTimelock + punishTimelock - timelock.content.blocks_left;
}
if (timelock.type === "Punish") {
return cancelTimelock + punishTimelock;
}
// We match all cases
return exhaustiveGuard(timelock);
}
export type BobStateNameRunningSwap = Exclude<
BobStateName,
| BobStateName.Started
@ -50,7 +87,11 @@ export type BobStateNameRunningSwap = Exclude<
>;
export type GetSwapInfoResponseExtRunningSwap = GetSwapInfoResponseExt & {
stateName: BobStateNameRunningSwap;
state_name: BobStateNameRunningSwap;
};
export type GetSwapInfoResponseExtWithTimelock = GetSwapInfoResponseExt & {
timelock: ExpiredTimelocks;
};
export function isBobStateNameRunningSwap(
@ -157,3 +198,14 @@ export function isGetSwapInfoResponseRunningSwap(
): response is GetSwapInfoResponseExtRunningSwap {
return isBobStateNameRunningSwap(response.state_name);
}
/**
* Type guard for GetSwapInfoResponseExt to ensure timelock is not null
* @param response The swap info response to check
* @returns True if the timelock exists, false otherwise
*/
export function isGetSwapInfoResponseWithTimelock(
response: GetSwapInfoResponseExt
): response is GetSwapInfoResponseExtWithTimelock {
return response.timelock !== null;
}