@atomiqlabs/sdk
Version:
atomiq labs SDK for cross-chain swaps between smart chains and bitcoin
548 lines (547 loc) • 22.2 kB
TypeScript
/// <reference types="node" />
/// <reference types="node" />
import { FromBTCLNDefinition, FromBTCLNWrapper } from "./FromBTCLNWrapper";
import { IFromBTCSelfInitSwap } from "../IFromBTCSelfInitSwap";
import { SwapType } from "../../../../enums/SwapType";
import { ChainType, SignatureData, SwapCommitState, SwapData } from "@atomiqlabs/base";
import { Buffer } from "buffer";
import { MinimalLightningNetworkWalletInterface } from "../../../../types/wallets/MinimalLightningNetworkWalletInterface";
import { IClaimableSwap } from "../../../IClaimableSwap";
import { IAddressSwap } from "../../../IAddressSwap";
import { IEscrowSelfInitSwapInit } from "../../IEscrowSelfInitSwap";
import { TokenAmount } from "../../../../types/TokenAmount";
import { BtcToken, SCToken } from "../../../../types/Token";
import { LoggerType } from "../../../../utils/Logger";
import { LNURLWithdraw } from "../../../../types/lnurl/LNURLWithdraw";
import { SwapExecutionActionSendToAddress, SwapExecutionActionSignSmartChainTx } from "../../../../types/SwapExecutionAction";
import { SwapExecutionStepPayment, SwapExecutionStepSettlement } from "../../../../types/SwapExecutionStep";
import { SwapStateInfo } from "../../../../types/SwapStateInfo";
/**
* State enum for legacy Lightning -> Smart chain swaps
* @category Swaps/Legacy/Lightning → Smart chain
*/
export declare enum FromBTCLNSwapState {
/**
* Swap has failed as the user didn't settle the HTLC on the destination before expiration
*/
FAILED = -4,
/**
* Swap has expired for good and there is no way how it can be executed anymore
*/
QUOTE_EXPIRED = -3,
/**
* A swap is almost expired, and it should be presented to the user as expired, though
* there is still a chance that it will be processed
*/
QUOTE_SOFT_EXPIRED = -2,
/**
* Swap HTLC on the destination chain has expired, it is not safe anymore to settle (claim) the
* swap on the destination smart chain.
*/
EXPIRED = -1,
/**
* Swap quote was created, use {@link FromBTCLNSwap.getAddress} or {@link FromBTCLNSwap.getHyperlink}
* to get the bolt11 lightning network invoice to pay to initiate the swap, then use the
* {@link FromBTCLNSwap.waitForPayment} to wait till the lightning network payment is received
* by the intermediary (LP)
*/
PR_CREATED = 0,
/**
* Lightning network payment has been received by the intermediary (LP), the user can now settle
* the swap on the destination smart chain side with {@link FromBTCLNSwap.commitAndClaim} (if
* the underlying chain supports it - check with {@link FromBTCLNSwap.canCommitAndClaimInOneShot}),
* or by calling {@link FromBTCLNSwap.commit} and {@link FromBTCLNSwap.claim} separately.
*/
PR_PAID = 1,
/**
* Swap escrow HTLC has been created on the destination chain. Continue by claiming it with the
* {@link FromBTCLNSwap.claim} or {@link FromBTCLNSwap.txsClaim} function.
*/
CLAIM_COMMITED = 2,
/**
* Swap successfully settled and funds received on the destination chain
*/
CLAIM_CLAIMED = 3
}
export type FromBTCLNSwapInit<T extends SwapData> = IEscrowSelfInitSwapInit<T> & {
pr?: string;
secret?: string;
initialSwapData: T;
lnurl?: string;
lnurlK1?: string;
lnurlCallback?: string;
};
export declare function isFromBTCLNSwapInit<T extends SwapData>(obj: any): obj is FromBTCLNSwapInit<T>;
/**
* Legacy escrow (HTLC) based swap for Bitcoin Lightning -> Smart chains, requires manual settlement
* of the swap on the destination network once the lightning network payment is received by the LP.
*
* @category Swaps/Legacy/Lightning → Smart chain
*/
export declare class FromBTCLNSwap<T extends ChainType = ChainType> extends IFromBTCSelfInitSwap<T, FromBTCLNDefinition<T>, FromBTCLNSwapState> implements IAddressSwap, IClaimableSwap<T, FromBTCLNDefinition<T>, FromBTCLNSwapState> {
protected readonly TYPE = SwapType.FROM_BTCLN;
/**
* @internal
*/
protected readonly swapStateName: (state: number) => string;
/**
* @internal
*/
protected readonly swapStateDescription: {
[-4]: string;
[-3]: string;
[-2]: string;
[-1]: string;
0: string;
1: string;
2: string;
3: string;
};
/**
* @internal
*/
protected readonly logger: LoggerType;
/**
* @internal
*/
protected readonly inputToken: BtcToken<true>;
private readonly lnurlFailSignal;
private readonly usesClaimHashAsId;
private readonly initialSwapData;
/**
* In case the swap is recovered from on-chain data, the pr saved here is just a payment hash,
* as it is impossible to retrieve the actual lightning network invoice paid purely from on-chain
* data
* @private
*/
private pr?;
private secret?;
private lnurl?;
private lnurlK1?;
private lnurlCallback?;
private prPosted?;
/**
* Sets the LNURL data for the swap
*
* @internal
*/
_setLNURLData(lnurl: string, lnurlK1: string, lnurlCallback: string): void;
constructor(wrapper: FromBTCLNWrapper<T>, init: FromBTCLNSwapInit<T["Data"]>);
constructor(wrapper: FromBTCLNWrapper<T>, obj: any);
/**
* @inheritDoc
* @internal
*/
protected getSwapData(): T["Data"];
/**
* @inheritDoc
* @internal
*/
protected upgradeVersion(): void;
/**
* @inheritDoc
* @internal
*/
protected getIdentifierHash(): Buffer;
/**
* Returns the payment hash of the swap and lightning network invoice, or `null` if not known (i.e. if
* the swap was recovered from on-chain data, the payment hash might not be known)
*
* @internal
*/
protected getPaymentHash(): Buffer | null;
/**
* @inheritDoc
* @internal
*/
protected canCommit(skipQuoteExpiryChecks?: boolean): boolean;
/**
* @inheritDoc
*/
getInputAddress(): string | null;
/**
* @inheritDoc
*/
getInputTxId(): string | null;
/**
* Returns the lightning network BOLT11 invoice that needs to be paid as an input to the swap.
*
* In case the swap is recovered from on-chain data, the address returned might be just a payment hash,
* as it is impossible to retrieve the actual lightning network invoice paid purely from on-chain
* data.
*/
getAddress(): string;
/**
* A hyperlink representation of the address + amount that the user needs to sends on the source chain.
* This is suitable to be displayed in a form of QR code.
*
* @remarks
* In case the swap is recovered from on-chain data, the address returned might be just a payment hash,
* as it is impossible to retrieve the actual lightning network invoice paid purely from on-chain
* data.
*/
getHyperlink(): string;
/**
* Returns the timeout time (in UNIX milliseconds) when the swap will definitelly be considered as expired
* if the LP doesn't make it expired sooner
*/
getDefinitiveExpiryTime(): number;
/**
* Returns timeout time (in UNIX milliseconds) when the swap htlc will expire
*/
getHtlcTimeoutTime(): number | null;
/**
* Returns timeout time (in UNIX milliseconds) when the LN invoice will expire
*/
getTimeoutTime(): number;
/**
* @inheritDoc
*/
isFinished(): boolean;
/**
* @inheritDoc
*/
isClaimable(): boolean;
/**
* @inheritDoc
*/
isSuccessful(): boolean;
/**
* @inheritDoc
*/
isFailed(): boolean;
/**
* @inheritDoc
*/
isInProgress(): boolean;
/**
* @inheritDoc
*/
isQuoteExpired(): boolean;
/**
* @inheritDoc
*/
isQuoteSoftExpired(): boolean;
/**
* @inheritDoc
* @internal
*/
_verifyQuoteDefinitelyExpired(): Promise<boolean>;
/**
* @inheritDoc
* @internal
*/
_verifyQuoteValid(): Promise<boolean>;
/**
* @inheritDoc
*/
getInputToken(): BtcToken<true>;
/**
* @inheritDoc
*/
getInput(): TokenAmount<BtcToken<true>>;
/**
* @inheritDoc
*/
getSmartChainNetworkFee(): Promise<TokenAmount<SCToken<T["ChainId"]>, true>>;
/**
* @inheritDoc
*/
hasEnoughForTxFees(): Promise<{
enoughBalance: boolean;
balance: TokenAmount<SCToken<T["ChainId"]>, true>;
required: TokenAmount<SCToken<T["ChainId"]>, true>;
}>;
private isValidSecretPreimage;
/**
* Sets the secret preimage for the swap, in case it is not known already
*
* @param secret Secret preimage that matches the expected payment hash
*
* @throws {Error} If an invalid secret preimage is provided
*/
setSecretPreimage(secret: string): void;
/**
* Returns whether the secret preimage for this swap is known
*/
hasSecretPreimage(): boolean;
/**
* Executes the swap with the provided bitcoin lightning network wallet or LNURL
*
* @param dstSigner Signer on the destination network, needs to have the same address as the one specified when
* quote was created, this is required for legacy swaps because the destination wallet needs to actively claim
* the swap funds on the destination (this also means you need native token to cover gas costs)
* @param walletOrLnurlWithdraw Bitcoin lightning wallet to use to pay the lightning network invoice, or an LNURL-withdraw
* link, wallet is not required and the LN invoice can be paid externally as well (just pass null or undefined here)
* @param callbacks Callbacks to track the progress of the swap
* @param options Optional options for the swap like feeRate, AbortSignal, and timeouts/intervals
* @param options.secret A swap secret to use for the claim transaction, generally only needed if the swap
* was recovered from on-chain data, or the pre-image was generated outside the SDK
*/
execute(dstSigner: T["Signer"] | T["NativeSigner"], walletOrLnurlWithdraw?: MinimalLightningNetworkWalletInterface | LNURLWithdraw | string | null | undefined, callbacks?: {
onSourceTransactionReceived?: (sourceTxId: string) => void;
onDestinationCommitSent?: (destinationCommitTxId: string) => void;
onDestinationClaimSent?: (destinationClaimTxId: string) => void;
onSwapSettled?: (destinationTxId: string) => void;
}, options?: {
abortSignal?: AbortSignal;
secret?: string;
lightningTxCheckIntervalSeconds?: number;
delayBetweenCommitAndClaimSeconds?: number;
}): Promise<boolean>;
/**
* @internal
*/
protected _getExecutionStatus(options?: {
secret?: string;
}): Promise<{
steps: [SwapExecutionStepPayment<"LIGHTNING">, SwapExecutionStepSettlement<T["ChainId"], "awaiting_manual">];
buildCurrentAction: (actionOptions?: {
skipChecks?: boolean;
}) => Promise<SwapExecutionActionSendToAddress<true> | SwapExecutionActionSignSmartChainTx<T> | undefined>;
state: FromBTCLNSwapState;
}>;
/**
* @internal
*/
private _buildLightningPaymentAction;
/**
* @inheritDoc
* @internal
*/
_submitExecutionTransactions(txs: (T["SignedTXType"] | string)[], abortSignal?: AbortSignal, requiredStates?: FromBTCLNSwapState[], idempotent?: boolean): Promise<string[]>;
/**
* @internal
*/
private _buildClaimSmartChainTxAction;
/**
* @inheritDoc
*
* @param options
* @param options.skipChecks Skip checks like making sure init signature is still valid and swap
* wasn't commited yet (this is handled on swap creation, if you commit right after quoting, you
* can use `skipChecks=true`)
* @param options.secret A swap secret to use for the claim transaction, generally only needed if the swap
* was recovered from on-chain data, or the pre-image was generated outside the SDK
*/
getExecutionAction(options?: {
skipChecks?: boolean;
secret?: string;
}): Promise<SwapExecutionActionSendToAddress<true> | SwapExecutionActionSignSmartChainTx<T> | undefined>;
/**
* @inheritDoc
*/
getExecutionStatus(options?: {
skipBuildingAction?: boolean;
skipChecks?: boolean;
secret?: string;
}): Promise<{
steps: [
SwapExecutionStepPayment<"LIGHTNING">,
SwapExecutionStepSettlement<T["ChainId"], "awaiting_manual">
];
currentAction: SwapExecutionActionSendToAddress<true> | SwapExecutionActionSignSmartChainTx<T> | undefined;
stateInfo: SwapStateInfo<FromBTCLNSwapState>;
}>;
/**
* @inheritDoc
*/
getExecutionSteps(): Promise<[
SwapExecutionStepPayment<"LIGHTNING">,
SwapExecutionStepSettlement<T["ChainId"], "awaiting_manual">
]>;
/**
* Checks whether the LP received the LN payment and we can continue by committing & claiming the HTLC on-chain
*
* @param save If the new swap state should be saved
*
* @internal
*/
_checkIntermediaryPaymentReceived(save?: boolean): Promise<boolean | null>;
/**
* Checks the data returned by the intermediary in the payment auth request
*
* @param signer Smart chain signer's address initiating the swap
* @param data Parsed swap data as returned by the intermediary
* @param signature Signature data as returned by the intermediary
*
* @throws {IntermediaryError} If the returned are not valid
* @throws {SignatureVerificationError} If the returned signature is not valid
* @throws {Error} If the swap is already committed on-chain
*
* @internal
*/
protected checkIntermediaryReturnedAuthData(signer: string, data: T["Data"], signature: SignatureData): Promise<void>;
/**
* Waits till a lightning network payment is received by the intermediary and client
* can continue by initiating (committing) & settling (claiming) the HTLC by calling
* either the {@link commitAndClaim} function (if the underlying chain allows commit
* and claim in a single transaction - check with {@link canCommitAndClaimInOneShot}).
* Or call {@link commit} and then {@link claim} separately.
*
* If this swap is using an LNURL-withdraw link as input, it automatically posts the
* generated invoice to the LNURL service to pay it.
*
* @param onPaymentReceived Callback as for when the LP reports having received the ln payment
* @param abortSignal Abort signal to stop waiting for payment
* @param checkIntervalSeconds How often to poll the intermediary for answer (default 5 seconds)
*/
waitForPayment(onPaymentReceived?: (txId: string) => void, checkIntervalSeconds?: number, abortSignal?: AbortSignal): Promise<boolean>;
/**
* @inheritDoc
*
* @throws {Error} If invalid signer is provided that doesn't match the swap data
*/
commit(_signer: T["Signer"] | T["NativeSigner"], abortSignal?: AbortSignal, skipChecks?: boolean, onBeforeTxSent?: (txId: string) => void): Promise<string>;
/**
* @inheritDoc
*/
waitTillCommited(abortSignal?: AbortSignal): Promise<void>;
/**
* Unsafe txs claim getter without state checking!
*
* @param _signer
* @param secret A swap secret to use for the claim transaction, generally only needed if the swap
* was recovered from on-chain data, or the pre-image was generated outside the SDK
*
* @internal
*/
private _txsClaim;
/**
* @inheritDoc
*
* @param _signer Optional signer address to use for claiming the swap, can also be different from the initializer
* @param secret A swap secret to use for the claim transaction, generally only needed if the swap
* was recovered from on-chain data, or the pre-image was generated outside the SDK
*
* @throws {Error} If in invalid state (must be {@link FromBTCLNSwapState.CLAIM_COMMITED})
*/
txsClaim(_signer?: string | T["Signer"] | T["NativeSigner"], secret?: string): Promise<T["TX"][]>;
/**
* @inheritDoc
*
* @param _signer
* @param abortSignal
* @param onBeforeTxSent
* @param secret A swap secret to use for the claim transaction, generally only needed if the swap
* was recovered from on-chain data, or the pre-image was generated outside the SDK
*/
claim(_signer: T["Signer"] | T["NativeSigner"], abortSignal?: AbortSignal, onBeforeTxSent?: (txId: string) => void, secret?: string): Promise<string>;
/**
* @inheritDoc
*
* @throws {Error} If swap is in invalid state (must be {@link FromBTCLNSwapState.CLAIM_COMMITED})
* @throws {Error} If the LP refunded sooner than we were able to claim
*/
waitTillClaimed(maxWaitTimeSeconds?: number, abortSignal?: AbortSignal): Promise<boolean>;
/**
* Estimated transaction fee for commit & claim transactions combined, required
* to settle the swap on the smart chain destination side.
*/
getCommitAndClaimNetworkFee(): Promise<TokenAmount<SCToken<T["ChainId"]>, true>>;
/**
* Returns whether the underlying chain supports calling commit and claim in a single call,
* such that you can use the {@link commitAndClaim} function. If not you have to manually
* call {@link commit} first and then {@link claim}.
*/
canCommitAndClaimInOneShot(): boolean;
/**
* Returns transactions for both commit & claim operation together, such that they can be signed all at once by
* the wallet. **WARNING**: transactions must be sent sequentially, such that the claim (2nd) transaction is only
* sent after the commit (1st) transaction confirms. Failure to do so can reveal the HTLC pre-image too soon,
* opening a possibility for the LP to steal funds!
*
* @param skipChecks Skip checks like making sure init signature is still valid and swap wasn't commited yet
* (this is handled when swap is created (quoted), if you commit right after quoting, you can use skipChecks=true)
* @param secret A swap secret to use for the claim transaction, generally only needed if the swap
* was recovered from on-chain data, or the pre-image was generated outside the SDK
*
* @throws {Error} If in invalid state (must be PR_PAID or CLAIM_COMMITED)
*/
txsCommitAndClaim(skipChecks?: boolean, secret?: string): Promise<T["TX"][]>;
/**
* Commits and claims the swap, in a way that the transactions can be signed together by the provided signer and
* then automatically sent sequentially by the SDK. To check if the underlying chain supports this flow check
* the {@link canCommitAndClaimInOneShot} function.
*
* @param _signer Signer to sign the transactions with, must be the same as used in the initialization
* @param abortSignal Abort signal to stop waiting for the transaction confirmation and abort
* @param skipChecks Skip checks like making sure init signature is still valid and swap wasn't commited yet
* (this is handled when swap is created (quoted), if you commit right after quoting, you can use skipChecks=true)
* @param onBeforeCommitTxSent Optional callback called before the initialization (commit) transaction is
* broadcasted
* @param onBeforeClaimTxSent Optional callback called before the settlement (claim) transaction is
* broadcasted
* @param secret A swap secret to use for the claim transaction, generally only needed if the swap
* was recovered from on-chain data, or the pre-image was generated outside the SDK
*
* @throws {Error} If in invalid state (must be PR_PAID or CLAIM_COMMITED)
* @throws {Error} If invalid signer is provided that doesn't match the swap data
*/
commitAndClaim(_signer: T["Signer"] | T["NativeSigner"], abortSignal?: AbortSignal, skipChecks?: boolean, onBeforeCommitTxSent?: (txId: string) => void, onBeforeClaimTxSent?: (txId: string) => void, secret?: string): Promise<string[]>;
/**
* Whether this swap uses an LNURL-withdraw link
*/
isLNURL(): boolean;
/**
* Gets the used LNURL or `null` if this is not an LNURL-withdraw swap
*/
getLNURL(): string | null;
/**
* Pay the generated lightning network invoice with an LNURL-withdraw link, this
* is useful when you want to display a lightning payment QR code and also want to
* allow payments using LNURL-withdraw NFC cards.
*
* Note that the swap needs to be created **without** an LNURL to begin with for this function
* to work. If this swap is already using an LNURL-withdraw link, this function throws.
*/
settleWithLNURLWithdraw(lnurl: string | LNURLWithdraw): Promise<void>;
/**
* @inheritDoc
*/
serialize(): any;
/**
* Checks the swap's state on-chain and compares it to its internal state, updates/changes it according to on-chain
* data
*
* @private
*/
private syncStateFromChain;
/**
* @inheritDoc
* @internal
*/
_shouldFetchExpiryStatus(): boolean;
/**
* @inheritDoc
* @internal
*/
_shouldFetchOnchainState(): boolean;
/**
* Whether an intermediary (LP) should be contacted to get the state of this swap.
*
* @internal
*/
_shouldCheckIntermediary(): boolean;
/**
* @inheritDoc
* @internal
*/
_sync(save?: boolean, quoteDefinitelyExpired?: boolean, commitStatus?: SwapCommitState, skipLpCheck?: boolean): Promise<boolean>;
/**
* @inheritDoc
* @internal
*/
_forciblySetOnchainState(commitStatus: SwapCommitState): Promise<boolean>;
/**
* @inheritDoc
* @internal
*/
_tick(save?: boolean): Promise<boolean>;
/**
* Forcibly sets the swap secret pre-image from on-chain data
*
* @internal
*/
_setSwapSecret(secret: string): void;
}