@atomiqlabs/sdk
Version:
atomiq labs SDK for cross-chain swaps between smart chains and bitcoin
296 lines (295 loc) • 10.7 kB
TypeScript
/// <reference types="node" />
/// <reference types="node" />
import { ChainEvent, ChainType } from "@atomiqlabs/base";
import { EventEmitter } from "events";
import { ISwap } from "./ISwap";
import { ISwapPrice } from "../prices/abstract/ISwapPrice";
import { UnifiedSwapEventListener } from "../events/UnifiedSwapEventListener";
import { SwapType } from "../enums/SwapType";
import { UnifiedSwapStorage } from "../storage/UnifiedSwapStorage";
import { SCToken } from "../types/Token";
import { PriceInfoType } from "../types/PriceInfoType";
import { IntermediaryAPI } from "../intermediaries/apis/IntermediaryAPI";
export declare const DEFAULT_MAX_PARALLEL_SWAP_TICKS = 50;
export declare const DEFAULT_MAX_PARALLEL_SWAP_SYNCS = 50;
/**
* Options for swap wrapper configuration
*
* @category Swaps/Base
*/
export type ISwapWrapperOptions = {
getRequestTimeout?: number;
postRequestTimeout?: number;
/**
* How many swaps to call `_tick()` for in parallel
*/
maxParallelSwapTicks?: number;
/**
* How many swaps to call `_sync()` for in parallel
*/
maxParallelSwapSyncs?: number;
/**
* Whether to save swaps that are not initialized into the persistent storage
*/
saveUninitializedSwaps?: boolean;
};
/**
* Token configuration for wrapper constructors
*
* @category Swaps/Base
*/
export type WrapperCtorTokens<T extends ChainType = ChainType> = {
[tokenAddress: string]: SCToken<T["ChainId"]>;
};
/**
* Type definition linking wrapper and swap types
*
* @category Swaps/Base
*/
export type SwapTypeDefinition<T extends ChainType, W extends ISwapWrapper<T, any>, S extends ISwap<T>> = {
Wrapper: W;
Swap: S;
};
/**
* Base abstract class for swap handler implementations
*
* @category Swaps/Base
*/
export declare abstract class ISwapWrapper<T extends ChainType, D extends SwapTypeDefinition<T, ISwapWrapper<T, D>, ISwap<T, D>>, O extends ISwapWrapperOptions = ISwapWrapperOptions> {
/**
* Swap type
*/
abstract readonly TYPE: SwapType;
/**
* Function for deserializing swaps
* @internal
*/
abstract readonly _swapDeserializer: new (wrapper: D["Wrapper"], data: any) => D["Swap"];
/**
* Logger instance
* @internal
*/
protected readonly logger: import("../utils/Logger").LoggerType;
/**
* Persistent storage backend for the swaps
* @internal
*/
protected readonly unifiedStorage: UnifiedSwapStorage<T>;
/**
* Smart chain events listener for listening to and parsing of on-chain events
* @internal
*/
protected readonly unifiedChainEvents: UnifiedSwapEventListener<T>;
/**
* States of the swaps where {@link ISwap._tick} should be called every second
* @internal
*/
protected readonly tickSwapState?: Array<D["Swap"]["_state"]>;
/**
* In-memory mapping of pending (not initiated) swaps, utilizing weak references to automatically
* free memory when swaps are dereferenced in not initiated state
* @internal
*/
protected readonly pendingSwaps: Map<string, WeakRef<D["Swap"]>>;
/**
* Whether this wrapper is initialized (have to call {@link init} to initialize a wrapper)
* @internal
*/
protected isInitialized: boolean;
/**
* An interval for calling tick functions on the underlying swaps
* @internal
*/
protected tickInterval?: NodeJS.Timeout;
/**
* An internal abort controller for the running tick handler
* @internal
*/
protected tickAbortController?: AbortController;
/**
* States of the swaps in pending (non-final state), these are checked automatically on initial swap synchronization
* @internal
*/
abstract readonly _pendingSwapStates: Array<D["Swap"]["_state"]>;
/**
* Chain interface of the underlying smart chain
* @internal
*/
readonly _chain: T["ChainInterface"];
/**
* Pricing API
* @internal
*/
readonly _prices: ISwapPrice;
/**
* Wrapper options
* @internal
*/
readonly _options: O;
/**
* Tokens indexed by their token address
* @internal
*/
readonly _tokens: {
[tokenAddress: string]: SCToken<T["ChainId"]>;
};
/**
* LP API Used to communicate with the LPs
* @internal
*/
readonly _lpApi: IntermediaryAPI;
/**
* Chain identifier string of this wrapper
*/
readonly chainIdentifier: T["ChainId"];
/**
* Event emitter emitting `"swapState"` event when swap's state changes
*/
readonly events: EventEmitter<{
swapState: [D["Swap"]];
}>;
constructor(chainIdentifier: T["ChainId"], unifiedStorage: UnifiedSwapStorage<T>, unifiedChainEvents: UnifiedSwapEventListener<T>, chain: T["ChainInterface"], prices: ISwapPrice, tokens: WrapperCtorTokens, lpApi: IntermediaryAPI, options: O, events?: EventEmitter<{
swapState: [ISwap];
}>);
/**
* Parses the provided gas amount from its `string` or `bigint` representation to `bigint` base units.
*
* Defaults to `0n` if no gasAmount is provided
*
* @param gasAmount
* @internal
*/
protected parseGasAmount(gasAmount?: string | bigint): bigint;
/**
* Pre-fetches swap price for a given swap
*
* @param amountData Amount data
* @param abortSignal Abort signal
* @returns Price of the token in uSats (micro sats)
* @internal
*/
protected preFetchPrice(amountData: {
token: string;
}, abortSignal?: AbortSignal): Promise<bigint | undefined>;
/**
* Pre-fetches bitcoin's USD price
*
* @param abortSignal Abort signal
* @internal
*/
protected preFetchUsdPrice(abortSignal?: AbortSignal): Promise<number | undefined>;
/**
* Verifies returned price for swaps
*
* @param lpServiceData Service data for the service in question (TO_BTCLN, TO_BTC, etc.) of the given intermediary
* @param send Whether this is a send (Smart chain -> Bitcoin) or receive (Bitcoin -> Smart chain) swap
* @param amountSats Amount in BTC
* @param amountToken Amount in token
* @param token Token used in the swap
* @param feeData Fee data as returned by the intermediary
* @param pricePrefetchPromise Optional price pre-fetch promise
* @param usdPricePrefetchPromise Optiona USD price pre-fetch promise
* @param abortSignal Abort signal
* @returns Price info object
* @throws {IntermediaryError} if the calculated fee is too high
*
* @internal
*/
protected verifyReturnedPrice(lpServiceData: {
swapBaseFee: number;
swapFeePPM: number;
}, send: boolean, amountSats: bigint, amountToken: bigint, token: string, feeData: {
networkFee?: bigint;
swapFeeBtc?: bigint;
}, pricePrefetchPromise?: Promise<bigint | undefined>, usdPricePrefetchPromise?: Promise<number | undefined>, abortSignal?: AbortSignal): Promise<PriceInfoType>;
/**
* Processes a single smart chain on-chain event
*
* @param event Smart chain event to process
* @param swap A swap related to the event
* @internal
*/
protected abstract processEvent?(event: ChainEvent<T["Data"]>, swap: D["Swap"]): Promise<void>;
/**
* Starts the interval calling the {@link ISwap._tick} on all the known swaps in tick-enabled states
* @internal
*/
protected startTickInterval(): void;
/**
* Runs checks on passed swaps, syncing their state from on-chain data
*
* @param pastSwaps Swaps to check
* @internal
*/
protected _checkPastSwaps(pastSwaps: D["Swap"][]): Promise<{
changedSwaps: D["Swap"][];
removeSwaps: D["Swap"][];
}>;
/**
* Initializes the swap wrapper, needs to be called before any other action can be taken
*
* @param noTimers Whether to skip scheduling a tick timer for the swaps, if the tick timer is not initiated
* the swap states depending on e.g. expiry can be out of sync with the actual expiration of the swap
* @param noCheckPastSwaps Whether to skip checking past swaps on initialization (by default all pending swaps
* are re-checked on init, and their state is synchronized from the on-chain data)
*/
init(noTimers?: boolean, noCheckPastSwaps?: boolean): Promise<void>;
/**
* Un-subscribes from event listeners on the smart chain, terminates the tick interval and stops this wrapper
*/
stop(): Promise<void>;
/**
* Runs checks on all the known pending swaps, syncing their state from on-chain data
*
* @remarks Doesn't work properly if you pass non-persisted swaps
*
* @param pastSwaps Optional array of past swaps to check, otherwise all relevant swaps will be fetched
* from the persistent storage
* @param noSave Whether to skip saving the swap changes in the persistent storage
*/
checkPastSwaps(pastSwaps?: D["Swap"][], noSave?: boolean): Promise<{
removeSwaps: D["Swap"][];
changedSwaps: D["Swap"][];
}>;
/**
* Invokes {@link ISwap._tick} on all the known swaps
*
* @param swaps Optional array of swaps to invoke `_tick()` on, otherwise all relevant swaps will be fetched
* from the persistent storage
* @param abortSignal Abort signal
*/
tick(swaps?: D["Swap"][], abortSignal?: AbortSignal): Promise<void>;
/**
* Returns the smart chain's native token used to pay for fees
* @internal
*/
_getNativeToken(): SCToken<T["ChainId"]>;
/**
* Saves the swap, if it is not initiated it is only saved to pending swaps
*
* @param swap Swap to save
*
* @internal
*/
_saveSwapData(swap: D["Swap"]): Promise<void>;
/**
* Removes the swap from the persistent storage and pending swaps
*
* @param swap Swap to remove
*
* @internal
*/
_removeSwapData(swap: D["Swap"]): Promise<void>;
/**
* Retrieves a swap by its ID from the pending swap mapping
*
* @param id
*
* @internal
*/
_getPendingSwap(id: string): D["Swap"] | null;
/**
* @internal
*/
_getSignerAddress(signer?: string | T["Signer"] | T["NativeSigner"]): Promise<string | undefined>;
}