UNPKG

xud

Version:
191 lines (190 loc) 9.24 kB
/// <reference types="node" /> import { EventEmitter } from 'events'; import { Models } from '../db/DB'; import { SwapDealInstance } from '../db/types'; import Logger from '../Logger'; import { OwnOrder, PeerOrder } from '../orderbook/types'; import * as packets from '../p2p/packets/types'; import Peer from '../p2p/Peer'; import Pool from '../p2p/Pool'; import SwapClientManager from './SwapClientManager'; import { ResolveRequest, SwapAccepted, SwapDeal, SwapSuccess } from './types'; export declare type OrderToAccept = Pick<SwapDeal, 'quantity' | 'price' | 'localId' | 'isBuy'> & { quantity: number; }; interface Swaps { on(event: 'swap.accepted', listener: (swapSuccess: SwapAccepted) => void): this; on(event: 'swap.paid', listener: (swapSuccess: SwapSuccess) => void): this; on(event: 'swap.failed', listener: (deal: SwapDeal) => void): this; on(event: 'swap.recovered', listener: (recoveredSwap: SwapDealInstance) => void): this; emit(event: 'swap.accepted', swapSuccess: SwapAccepted): boolean; emit(event: 'swap.paid', swapSuccess: SwapSuccess): boolean; emit(event: 'swap.failed', deal: SwapDeal): boolean; emit(event: 'swap.recovered', recoveredSwap: SwapDealInstance): boolean; } declare class Swaps extends EventEmitter { swapClientManager: SwapClientManager; /** A map between payment hashes and pending sanity swaps. */ private sanitySwaps; private logger; private models; private pool; private strict; /** A map between payment hashes and swap deals. */ private deals; private swapRecovery; /** A map between payment hashes and timeouts for swaps. */ private timeouts; private usedHashes; private repository; /** The maximum time in milliseconds we will wait for a swap to be accepted before failing it. */ private static readonly SWAP_ACCEPT_TIMEOUT; /** The maximum time in milliseconds we will wait for a swap to be completed before failing it. */ private static readonly SWAP_COMPLETE_TIMEOUT; /** * Additional time that the maker will wait for a swap to be completed before considering it timed * out. This exists because the maker starts timing sooner and ends timing later than the taker. * The maker starts timing as soon as it sends its SwapAccepted packet, but taker starts upon * receiving that packet some short time later. Furthermore, the taker stops the timer as soon as * it reveals the preimage and settles its incoming payment, whereas the maker doesn't stop until * it receives the preimage. */ private static readonly SWAP_COMPLETE_MAKER_BUFFER; /** * The time threshold in milliseconds after which we consider a counterparty abusive if they * settle payment for a timed out swap. */ private static readonly SWAP_ABUSE_TIME_LIMIT; /** The maximum time in milliseconds we will wait to receive an expected sanity swap init packet. */ private static readonly SANITY_SWAP_INIT_TIMEOUT; /** The maximum time in milliseconds we will wait for a swap to be completed before failing it. */ private static readonly SANITY_SWAP_COMPLETE_TIMEOUT; constructor({ logger, models, pool, swapClientManager, strict }: { logger: Logger; models: Models; pool: Pool; swapClientManager: SwapClientManager; strict?: boolean; }); /** * Checks if a swap request is valid. This is a shallow check that only detects critical * inconsistencies and verifies only whether the request can possibly lead to a successful swap. * @returns `true` if the request is valid, otherwise `false` */ static validateSwapRequest: ({ proposedQuantity, rHash }: packets.SwapRequestPacketBody) => boolean; /** * Calculates the minimum expected lock delta for the final hop of the first leg to ensure a * very high probability that it won't expire before the second leg payment. We use a Poisson * distribution to model the possible block times of two independent chains, first calculating * a probabilistic upper bound for the lock time in minuntes of the second leg then a * probabilistic lower bound for the number of blocks for the lock time extended to the final * hop of the first leg. * @param secondLegLockDuration The lock duration (aka time lock or cltv delta) of the second * leg (maker to taker) denominated in blocks of that chain. * @returns A number of blocks for the chain of the first leg that is highly likely to take * more time in minutes than the provided second leg lock duration. */ private static calculateLockBuffer; /** * Calculates the currencies and amounts of subunits/satoshis each side of a swap should receive. * @param quantity The quantity being swapped * @param price The price for the swap * @param isBuy Whether the maker order in the swap is a buy * @returns An object with the calculated maker and taker values. */ private static calculateMakerTakerAmounts; init: () => Promise<void>; private bind; /** * Checks if there are connected swap clients for both currencies in a given trading pair. * @returns `undefined` if both currencies are active, otherwise the ticker symbol for an inactive currency. */ checkInactiveCurrencyClients: (pairId: string) => string | undefined; /** * Sends a swap failed packet to the counterparty peer in a swap with details about the error * that caused the failure. Sets reqId if packet is a response to a request. */ private sendErrorToPeer; /** * Saves deal to database and deletes it from memory if it is no longer active. * @param deal The deal to persist. */ private persistDeal; getPendingSwapHashes: () => string[]; /** * Gets a deal by its rHash value. * @param rHash The rHash value of the deal to get. * @returns A deal if one is found, otherwise undefined. */ getDeal: (rHash: string) => SwapDeal | undefined; addDeal: (deal: SwapDeal) => void; /** * Checks if a swap for two given orders can be executed by ensuring both swap clients are active * and if there exists a route to the maker. * @param maker maker order * @param taker taker order * @returns `void` if the swap can be executed, throws a [[SwapFailureReason]] otherwise */ private verifyExecution; /** * A promise wrapper for a swap procedure * @param maker the remote maker order we are filling * @param taker our local taker order * @returns A promise that resolves to a [[SwapSuccess]] once the swap is completed, throws a [[SwapFailureReason]] if it fails */ executeSwap: (maker: PeerOrder, taker: OwnOrder) => Promise<SwapSuccess>; /** * Executes a sanity swap with a peer for a specified currency. * @returns `true` if the swap succeeds, otherwise `false` */ executeSanitySwap: (currency: string, peer: Peer) => Promise<boolean>; /** * Begins a swap to fill an order by sending a [[SwapRequestPacket]] to the maker. * @param maker The remote maker order we are filling * @param taker Our local taker order * @returns The rHash for the swap, or a [[SwapFailureReason]] if the swap could not be initiated */ private beginSwap; /** * Accepts a proposed deal for a specified amount if a route and CLTV delta could be determined * for the swap. Stores the deal in the local collection of deals. * @returns A promise resolving to `true` if the deal was accepted, `false` otherwise. */ acceptDeal: (orderToAccept: OrderToAccept, requestPacket: packets.SwapRequestPacket, peer: Peer) => Promise<boolean>; private handleHtlcAccepted; /** * Handles a response from a peer to confirm a swap deal and updates the deal. If the deal is * accepted, initiates the swap. */ private handleSwapAccepted; /** * Verifies that the resolve request is valid. Checks the received amount vs * the expected amount. * @returns `true` if the resolve request is valid, `false` otherwise */ private validateResolveRequest; /** Attempts to resolve the preimage for the payment hash of a pending sanity swap. */ private resolveSanitySwap; /** * Resolves the hash for an incoming HTLC to its preimage. * @param rHash the payment hash to resolve * @param amount the amount in satoshis * @param htlcCurrency the currency of the HTLC * @returns the preimage for the provided payment hash */ resolveHash: (rHash: string, amount: number, htlcCurrency?: string | undefined) => Promise<string>; handleResolveRequest: (resolveRequest: ResolveRequest) => Promise<string>; private handleSwapTimeout; /** * Fails a deal and optionally sends a SwapFailurePacket to a peer, if provided. */ private failDeal; /** * Updates the phase of a swap deal and handles logic directly related to that phase change, * including persisting the deal state to the database. */ private setDealPhase; private handleSwapFailed; close: () => void; } export default Swaps;