UNPKG

@arkade-os/boltz-swap

Version:

A production-ready TypeScript package that brings Boltz submarine-swaps to Arkade.

263 lines (261 loc) 8.48 kB
import { SWAP_POLL_TASK_TYPE } from "../chunk-HIG2OOAN.js"; import { ArkadeSwaps } from "../chunk-VKHFXGKL.js"; import "../chunk-SJQJQO7P.js"; // src/expo/arkade-lightning.ts import { getRandomId } from "@arkade-os/sdk"; function warnOnRemovedBackgroundFields(bg) { if (!bg || typeof bg !== "object") return; const removed = []; if ("taskName" in bg) removed.push("taskName"); if ("minimumBackgroundInterval" in bg) { removed.push("minimumBackgroundInterval"); } if (removed.length === 0) return; console.warn( `[boltz-swap] ExpoArkadeSwaps.setup: ignoring removed background field(s): ${removed.join(", ")}. OS-task registration moved to "@arkade-os/boltz-swap/expo/background". See https://github.com/arkade-os/boltz-swap/issues/136` ); } var ExpoArkadeSwaps = class _ExpoArkadeSwaps { constructor(inner, config) { this.inner = inner; this.config = config; this.swapRepository = inner.swapRepository; } swapRepository; foregroundIntervalId; /** * Create an ExpoArkadeSwaps with foreground/background queue handoff. * * 1. Creates the inner {@link ArkadeSwaps} with SwapManager enabled. * 2. Persists {@link PersistedSwapBackgroundConfig} for background rehydration. * 3. Seeds the task queue with a swap-poll task. * 4. Starts the foreground interval (if configured). * * OS-level scheduling lives in * `@arkade-os/boltz-swap/expo/background` and is invoked separately * by the consumer. */ static async setup(config) { warnOnRemovedBackgroundFields(config.background); const inner = new ArkadeSwaps({ ...config, swapManager: config.swapManager ?? true }); const { taskQueue } = config.background; const derivedArkServerUrl = inner.arkProvider.serverUrl; const arkServerUrl = config.arkServerUrl ?? derivedArkServerUrl; if (!arkServerUrl) { throw new Error( "Ark server URL is required for Expo background rehydration. Pass `arkServerUrl` to ExpoArkadeSwaps.setup()." ); } const bgConfig = { boltzApiUrl: config.swapProvider.getApiUrl(), arkServerUrl, network: config.swapProvider.getNetwork() }; await taskQueue.persistConfig(bgConfig); const instance = new _ExpoArkadeSwaps(inner, config); await instance.seedSwapPollTask(); if (config.background.foregroundIntervalMs && config.background.foregroundIntervalMs > 0) { instance.startForegroundPolling(config.background.foregroundIntervalMs); } return instance; } // ── Foreground polling ─────────────────────────────────────────── startForegroundPolling(intervalMs) { this.foregroundIntervalId = setInterval(() => { this.runForegroundPoll().catch(console.error); }, intervalMs); } async runForegroundPoll() { const { taskQueue } = this.config.background; const results = await taskQueue.getResults(); if (results.length > 0) { await taskQueue.acknowledgeResults(results.map((r) => r.id)); } await this.seedSwapPollTask(); } async seedSwapPollTask() { const { taskQueue } = this.config.background; const existing = await taskQueue.getTasks(SWAP_POLL_TASK_TYPE); if (existing.length > 0) return; const task = { id: getRandomId(), type: SWAP_POLL_TASK_TYPE, data: {}, createdAt: Date.now() }; await taskQueue.addTask(task); } // ── Lifecycle ──────────────────────────────────────────────────── /** * Reset all swap state: stops polling and clears the swap repository. * * **Destructive** — any swap in a non-terminal state will lose its * refund/claim path. Intended for wallet-reset / dev / test scenarios only. */ async reset() { await this.dispose(); await this.inner.swapRepository.clear(); } async dispose() { if (this.foregroundIntervalId) { clearInterval(this.foregroundIntervalId); this.foregroundIntervalId = void 0; } await this.inner.dispose(); } async [Symbol.asyncDispose]() { await this.dispose(); } // ── IArkadeSwaps delegation ────────────────────────────────────── startSwapManager() { return this.inner.startSwapManager(); } stopSwapManager() { return this.inner.stopSwapManager(); } getSwapManager() { return this.inner.getSwapManager(); } createLightningInvoice(args) { return this.inner.createLightningInvoice(args); } sendLightningPayment(args) { return this.inner.sendLightningPayment(args); } createSubmarineSwap(args) { return this.inner.createSubmarineSwap(args); } createReverseSwap(args) { return this.inner.createReverseSwap(args); } claimVHTLC(pendingSwap) { return this.inner.claimVHTLC(pendingSwap); } refundVHTLC(pendingSwap) { return this.inner.refundVHTLC(pendingSwap); } inspectSubmarineRecovery(swap) { return this.inner.inspectSubmarineRecovery(swap); } scanRecoverableSubmarineSwaps() { return this.inner.scanRecoverableSubmarineSwaps(); } recoverSubmarineFunds(swap) { return this.inner.recoverSubmarineFunds(swap); } recoverAllSubmarineFunds(swaps) { return this.inner.recoverAllSubmarineFunds(swaps); } waitAndClaim(pendingSwap) { return this.inner.waitAndClaim(pendingSwap); } waitForSwapSettlement(pendingSwap) { return this.inner.waitForSwapSettlement(pendingSwap); } waitForSwapFunded(pendingSwap) { return this.inner.waitForSwapFunded(pendingSwap); } restoreSwaps(boltzFees) { return this.inner.restoreSwaps(boltzFees); } enrichReverseSwapPreimage(swap, preimage) { return this.inner.enrichReverseSwapPreimage(swap, preimage); } enrichSubmarineSwapInvoice(swap, invoice) { return this.inner.enrichSubmarineSwapInvoice(swap, invoice); } // ── Chain swap delegation ──────────────────────────────────────── arkToBtc(args) { return this.inner.arkToBtc(args); } waitAndClaimBtc(pendingSwap) { return this.inner.waitAndClaimBtc(pendingSwap); } claimBtc(pendingSwap) { return this.inner.claimBtc(pendingSwap); } refundArk(pendingSwap) { return this.inner.refundArk(pendingSwap); } btcToArk(args) { return this.inner.btcToArk(args); } waitAndClaimArk(pendingSwap) { return this.inner.waitAndClaimArk(pendingSwap); } claimArk(pendingSwap) { return this.inner.claimArk(pendingSwap); } signCooperativeClaimForServer(pendingSwap) { return this.inner.signCooperativeClaimForServer(pendingSwap); } waitAndClaimChain(pendingSwap) { return this.inner.waitAndClaimChain(pendingSwap); } createChainSwap(args) { return this.inner.createChainSwap(args); } verifyChainSwap(args) { return this.inner.verifyChainSwap(args); } quoteSwap(swapId, options) { return this.inner.quoteSwap(swapId, options); } getSwapQuote(swapId) { return this.inner.getSwapQuote(swapId); } acceptSwapQuote(swapId, amount, options) { return this.inner.acceptSwapQuote(swapId, amount, options); } joinBatch(identity, input, output, arkInfo, isRecoverable) { return this.inner.joinBatch(identity, input, output, arkInfo, isRecoverable); } createVHTLCScript(params) { return this.inner.createVHTLCScript(params); } getFees(from, to) { if (from !== void 0 && to !== void 0) { return this.inner.getFees(from, to); } return this.inner.getFees(); } getLimits(from, to) { if (from !== void 0 && to !== void 0) { return this.inner.getLimits(from, to); } return this.inner.getLimits(); } getSwapStatus(swapId) { return this.inner.getSwapStatus(swapId); } getPendingSubmarineSwaps() { return this.inner.getPendingSubmarineSwaps(); } getPendingReverseSwaps() { return this.inner.getPendingReverseSwaps(); } getPendingChainSwaps() { return this.inner.getPendingChainSwaps(); } getSwapHistory() { return this.inner.getSwapHistory(); } refreshSwapsStatus() { return this.inner.refreshSwapsStatus(); } }; var ExpoArkadeLightning = ExpoArkadeSwaps; export { ExpoArkadeLightning, ExpoArkadeSwaps, SWAP_POLL_TASK_TYPE };