UNPKG

@atomiqlabs/sdk

Version:

atomiq labs SDK for cross-chain swaps between smart chains and bitcoin

139 lines (129 loc) 5.32 kB
import {IToBTCSwap, ToBTCSwapState} from "./IToBTCSwap"; import {ChainType, ClaimEvent, InitializeEvent, RefundEvent} from "@atomiqlabs/base"; import {ISwapWrapperOptions, SwapTypeDefinition} from "../../ISwapWrapper"; import {Intermediary, SingleChainReputationType} from "../../../intermediaries/Intermediary"; import {IntermediaryError} from "../../../errors/IntermediaryError"; import {IEscrowSwapWrapper} from "../IEscrowSwapWrapper"; import {AmountData} from "../../../types/AmountData"; import {mapArrayToObject} from "../../../utils/Utils"; export type IToBTCDefinition<T extends ChainType, W extends IToBTCWrapper<T, any>, S extends IToBTCSwap<T>> = SwapTypeDefinition<T, W, S>; /** * Base class for wrappers of escrow-based Smart chain -> Bitcoin (on-chain & lightning) swaps * * @category Swaps/Smart chain → Bitcoin */ export abstract class IToBTCWrapper< T extends ChainType, D extends IToBTCDefinition<T, IToBTCWrapper<T, D>, IToBTCSwap<T, D>>, O extends ISwapWrapperOptions = ISwapWrapperOptions > extends IEscrowSwapWrapper<T, D, O> { /** * @internal */ protected readonly tickSwapState = [ToBTCSwapState.CREATED, ToBTCSwapState.COMMITED, ToBTCSwapState.SOFT_CLAIMED]; /** * @internal */ readonly _pendingSwapStates = [ ToBTCSwapState.CREATED, ToBTCSwapState.QUOTE_SOFT_EXPIRED, ToBTCSwapState.COMMITED, ToBTCSwapState.SOFT_CLAIMED, ToBTCSwapState.REFUNDABLE ]; /** * @internal */ readonly _refundableSwapStates = [ToBTCSwapState.REFUNDABLE]; /** * Pre-fetches intermediary's reputation, doesn't throw, instead aborts via abortController and returns null * * @param amountData * @param lp Intermediary * @param abortController * @param contractVersion * @returns Intermediary's reputation or null if failed * @throws {IntermediaryError} If the intermediary vault doesn't exist * * @internal */ protected preFetchIntermediaryReputation( amountData: Omit<AmountData, "amount">, lp: Intermediary, abortController: AbortController, contractVersion: string ): Promise<SingleChainReputationType | undefined> { return lp.getReputation(this.chainIdentifier, this._contract(contractVersion), [amountData.token.toString()], abortController.signal).then(res => { if(res==null) throw new IntermediaryError("Invalid data returned - invalid LP vault"); return res; }).catch(e => { this.logger.warn("preFetchIntermediaryReputation(): Error: ", e); abortController.abort(e); return undefined; }); } /** * Pre-fetches feeRate for a given swap * * @param signer Address of the swap initiator * @param amountData * @param claimHash optional hash of the swap or null * @param abortController * @param contractVersions * @returns Fee rate * * @internal */ protected preFetchFeeRate( signer: string, amountData: Omit<AmountData, "amount">, claimHash: {[contractVersion: string]: string} | undefined, abortController: AbortController, contractVersions: string[] ): {[contractVersion: string]: Promise<string | undefined>} { return mapArrayToObject(contractVersions, (contractVersion) => { return this._contract(contractVersion).getInitPayInFeeRate(signer, this._chain.randomAddress(), amountData.token, claimHash?.[contractVersion]) .catch(e => { this.logger.warn("preFetchFeeRate(): Error: ", e); abortController.abort(e); return undefined; }); }); } /** * @internal */ protected async processEventInitialize(swap: D["Swap"], event: InitializeEvent<T["Data"]>): Promise<boolean> { if(swap._state===ToBTCSwapState.CREATED || swap._state===ToBTCSwapState.QUOTE_SOFT_EXPIRED) { swap._state = ToBTCSwapState.COMMITED; return true; } return false; } /** * @internal */ protected async processEventClaim(swap: D["Swap"], event: ClaimEvent<T["Data"]>): Promise<boolean> { if(swap._state!==ToBTCSwapState.REFUNDED && swap._state!==ToBTCSwapState.CLAIMED) { await swap._setPaymentResult({ secret: event.result, txId: Buffer.from(event.result, "hex").reverse().toString("hex") }).catch(e => { this.logger.warn(`processEventClaim(): Failed to set payment result ${event.result}: `, e); }); swap._state = ToBTCSwapState.CLAIMED; return true; } return false; } /** * @internal */ protected processEventRefund(swap: D["Swap"], event: RefundEvent<T["Data"]>): Promise<boolean> { if(swap._state!==ToBTCSwapState.CLAIMED && swap._state!==ToBTCSwapState.REFUNDED) { swap._state = ToBTCSwapState.REFUNDED; return Promise.resolve(true); } return Promise.resolve(false); } }