@arkade-os/boltz-swap
Version:
A production-ready TypeScript package that brings Boltz submarine-swaps to Arkade.
263 lines (261 loc) • 8.48 kB
JavaScript
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
};