UNPKG

@atomiqlabs/sdk

Version:

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

260 lines (259 loc) 11.9 kB
/// <reference types="node" /> import { ISwapWrapper, ISwapWrapperOptions, SwapTypeDefinition, WrapperCtorTokens } from "../ISwapWrapper"; import { BitcoinRpcWithAddressIndex, BtcBlock, BtcRelay, ChainEvent, ChainType, RelaySynchronizer, SpvVaultData, SpvWithdrawalClaimedState, SpvWithdrawalFrontedState } from "@atomiqlabs/base"; import { SpvFromBTCSwap, SpvFromBTCSwapState } from "./SpvFromBTCSwap"; import { BTC_NETWORK } from "@scure/btc-signer/utils"; import { SwapType } from "../../enums/SwapType"; import { UnifiedSwapStorage } from "../../storage/UnifiedSwapStorage"; import { UnifiedSwapEventListener } from "../../events/UnifiedSwapEventListener"; import { ISwapPrice } from "../../prices/abstract/ISwapPrice"; import { EventEmitter } from "events"; import { Intermediary } from "../../intermediaries/Intermediary"; import { IntermediaryAPI } from "../../intermediaries/apis/IntermediaryAPI"; import { CoinselectAddressTypes } from "../../bitcoin/coinselect2"; import { Transaction } from "@scure/btc-signer"; import { ISwap } from "../ISwap"; import { IClaimableSwapWrapper } from "../IClaimableSwapWrapper"; import { AllOptional } from "../../utils/TypeUtils"; import { BitcoinWalletUtxoBase } from "../../bitcoin/wallet/IBitcoinWallet"; export type SpvFromBTCOptions = { /** * Optional additional native token to receive as an output of the swap (e.g. STRK on Starknet or cBTC on Citrea). * * When passed as a `bigint` it is specified in base units of the token and in `string` it is the human readable * decimal format. */ gasAmount?: bigint | string; /** * The LP enforces a minimum bitcoin fee rate in sats/vB for the swap transaction. With this config you can optionally * limit how high of a minimum fee rate would you accept. * * By default the maximum allowed fee rate is calculated dynamically based on current bitcoin fee rate as: * * `maxAllowedBitcoinFeeRate` = 10 + `currentBitcoinFeeRate` * 1.5 */ maxAllowedBitcoinFeeRate?: number; /** * A flag to attach 0 watchtower fee to the swap, this would make the settlement unattractive for the watchtowers * and therefore automatic settlement for such swaps will not be possible, you will have to settle manually * with {@link FromBTCLNSwap.claim} or {@link FromBTCLNSwap.txsClaim} functions. */ unsafeZeroWatchtowerFee?: boolean; /** * A safety factor to use when estimating the watchtower fee to attach to the swap (this has to cover the gas fee * of watchtowers settling the swap). A higher multiple here would mean that a swap is more attractive for * watchtowers to settle automatically. * * Uses a `1.25` multiple by default (i.e. the current network fee is multiplied by 1.25 and then used to estimate * the settlement gas fee cost) */ feeSafetyFactor?: number; /** * Instruct the LP to create a "sticky address" for your destination wallet address. After the first successful * swap with that LP, the used bitcoin address will be permanently linked to your destination wallet address. So * all subsequent swaps to the same address will yield the same LP deposit bitcoin address. Useful for corporate * whitelist-only wallets */ stickyAddress?: boolean; /** * A bitcoin wallet UTXOs to fully use as an input for this swap, use this option along with passing `amount` as * `undefined` when you want to swap the full BTC balance of the wallet in a single swap */ sourceWalletUtxos?: BitcoinWalletUtxoBase[] | Promise<BitcoinWalletUtxoBase[]>; /** * Bitcoin fee rate to use when deriving `maxAllowedBitcoinFeeRate` and when calculating the input amount based * on the `sourceWalletUtxos` */ bitcoinFeeRate?: Promise<number> | number; /** * @deprecated Use `maxAllowedBitcoinFeeRate` instead! */ maxAllowedNetworkFeeRate?: number; }; export type SpvFromBTCWrapperOptions = ISwapWrapperOptions & { maxConfirmations: number; bitcoinNetwork: BTC_NETWORK; bitcoinBlocktime: number; maxTransactionsDelta: number; maxRawAmountAdjustmentDifferencePPM: number; maxBtcFeeMultiplier: number; maxBtcFeeOffset: number; }; export type SpvFromBTCTypeDefinition<T extends ChainType> = SwapTypeDefinition<T, SpvFromBTCWrapper<T>, SpvFromBTCSwap<T>>; export declare const REQUIRED_SPV_SWAP_VAULT_ADDRESS_TYPE: CoinselectAddressTypes; export declare const REQUIRED_SPV_SWAP_LP_ADDRESS_TYPE: CoinselectAddressTypes; /** * New spv vault (UTXO-controlled vault) based swaps for Bitcoin -> Smart chain swaps not requiring * any initiation on the destination chain, and with the added possibility for the user to receive * a native token on the destination chain as part of the swap (a "gas drop" feature). * * @category Swaps/Bitcoin → Smart chain */ export declare class SpvFromBTCWrapper<T extends ChainType> extends ISwapWrapper<T, SpvFromBTCTypeDefinition<T>, SpvFromBTCWrapperOptions> implements IClaimableSwapWrapper<SpvFromBTCSwap<T>> { readonly TYPE: SwapType.SPV_VAULT_FROM_BTC; /** * @internal */ readonly _claimableSwapStates: SpvFromBTCSwapState[]; /** * @internal */ readonly _swapDeserializer: typeof SpvFromBTCSwap; /** * @internal */ protected readonly btcRelay: (version?: string) => BtcRelay<any, T["TX"], any>; /** * @internal */ protected readonly tickSwapState: Array<SpvFromBTCSwap<T>["_state"]>; /** * @internal */ readonly _synchronizer: (version?: string) => RelaySynchronizer<any, T["TX"], any>; /** * @internal */ readonly _contract: (version?: string) => T["SpvVaultContract"]; /** * @internal */ readonly _btcRpc: BitcoinRpcWithAddressIndex<BtcBlock>; /** * @internal */ readonly _spvWithdrawalDataDeserializer: (version?: string) => (new (data: any) => T["SpvVaultWithdrawalData"]); /** * @internal */ readonly _pendingSwapStates: Array<SpvFromBTCSwap<T>["_state"]>; private readonly versionedContracts; private readonly versionedSynchronizer; /** * @param chainIdentifier * @param unifiedStorage Storage interface for the current environment * @param unifiedChainEvents On-chain event listener * @param chain * @param prices Pricing to use * @param tokens * @param versionedContracts * @param versionedSynchronizer * @param btcRpc Bitcoin RPC which also supports getting transactions by txoHash * @param lpApi * @param options * @param events Instance to use for emitting events */ constructor(chainIdentifier: string, unifiedStorage: UnifiedSwapStorage<T>, unifiedChainEvents: UnifiedSwapEventListener<T>, chain: T["ChainInterface"], prices: ISwapPrice, tokens: WrapperCtorTokens, versionedContracts: { [version: string]: { btcRelay: BtcRelay<any, T["TX"], any>; spvVaultContract: T["SpvVaultContract"]; spvVaultWithdrawalDataConstructor: new (data: any) => T["SpvVaultWithdrawalData"]; }; }, versionedSynchronizer: { [version: string]: { synchronizer: RelaySynchronizer<any, T["TX"], any>; }; }, btcRpc: BitcoinRpcWithAddressIndex<any>, lpApi: IntermediaryAPI, options?: AllOptional<SpvFromBTCWrapperOptions>, events?: EventEmitter<{ swapState: [ISwap]; }>); private processEventFront; private processEventClaim; private processEventClose; /** * @inheritDoc * @internal */ protected processEvent(event: ChainEvent<T["Data"]>, swap: SpvFromBTCSwap<T>): Promise<void>; /** * Pre-fetches latest finalized block height of the smart chain * * @param abortController * @private */ private preFetchFinalizedBlockHeight; /** * Pre-fetches caller (watchtower) bounty data for the swap. Doesn't throw, instead returns null and aborts the * provided abortController * * @param amountData * @param options Options as passed to the swap creation function * @param abortController * @param contractVersion * @private */ private preFetchCallerFeeInNativeToken; /** * Pre-fetches caller (watchtower) bounty data for the swap. Doesn't throw, instead returns null and aborts the * provided abortController * * @param amountPrefetch * @param totalFeeInNativeTokenPrefetch * @param amountData * @param options Options as passed to the swap creation function * @param pricePrefetch * @param nativeTokenPricePrefetch * @param abortSignal * @private */ private computeCallerFeeShare; /** * Verifies response returned from intermediary * * @param resp Response as returned by the intermediary * @param amountData * @param lp Intermediary * @param options Options as passed to the swap creation function * @param callerFeeShare * @param maxBitcoinFeeRatePromise Maximum accepted fee rate from the LPs * @param bitcoinFeeRatePromise * @param abortSignal * @private * @throws {IntermediaryError} in case the response is invalid */ private verifyReturnedData; private amountPrefetch; private bitcoinFeeRatePrefetch; /** * Returns a newly created Bitcoin -> Smart chain swap using the SPV vault (UTXO-controlled vault) swap protocol, * with the passed amount. Also allows specifying additional "gas drop" native token that the receipient receives * on the destination chain in the `options` argument. * * @param recipient Recipient address on the destination smart chain * @param amountData Amount, token and exact input/output data for to swap * @param lps An array of intermediaries (LPs) to get the quotes from * @param options Optional additional quote options * @param additionalParams Optional additional parameters sent to the LP when creating the swap * @param abortSignal Abort signal */ create(recipient: string, amountData: { amount?: bigint; token: string; exactIn: boolean; }, lps: Intermediary[], options?: SpvFromBTCOptions, additionalParams?: Record<string, any>, abortSignal?: AbortSignal): { quote: Promise<SpvFromBTCSwap<T>>; intermediary: Intermediary; }[]; /** * Recovers an SPV vault (UTXO-controlled vault) based swap from smart chain on-chain data * * @param state State of the spv vault withdrawal recovered from on-chain data * @param vault SPV vault processing the swap * @param lp Intermediary (LP) used as a counterparty for the swap */ recoverFromState(state: SpvWithdrawalClaimedState | SpvWithdrawalFrontedState, contractVersion: string, vault?: SpvVaultData | null, lp?: Intermediary): Promise<SpvFromBTCSwap<T> | null>; /** * Returns a random dummy PSBT that can be used for fee estimation, the last output (the LP output) is omitted * to allow for coinselection algorithm to determine maximum sendable amount there * * @param includeGasToken Whether to return the PSBT also with the gas token amount (increases the vSize by 8) */ getDummySwapPsbt(includeGasToken?: boolean): Transaction; /** * @inheritDoc * @internal */ protected _checkPastSwaps(pastSwaps: SpvFromBTCSwap<T>[]): Promise<{ changedSwaps: SpvFromBTCSwap<T>[]; removeSwaps: SpvFromBTCSwap<T>[]; }>; }