@atomiqlabs/sdk
Version:
atomiq labs SDK for cross-chain swaps between smart chains and bitcoin
131 lines (130 loc) • 5.56 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.IFromBTCLNWrapper = void 0;
const IFromBTCWrapper_1 = require("./IFromBTCWrapper");
const buffer_1 = require("buffer");
const Utils_1 = require("../../../utils/Utils");
const IntermediaryError_1 = require("../../../errors/IntermediaryError");
const LNURL_1 = require("../../../lnurl/LNURL");
const UserError_1 = require("../../../errors/UserError");
const sha256_1 = require("@noble/hashes/sha256");
/**
* Base class for wrappers of escrow-based Lightning -> Smart chain swaps
*
* @category Swaps/Abstract
*/
class IFromBTCLNWrapper extends IFromBTCWrapper_1.IFromBTCWrapper {
/**
* @param chainIdentifier
* @param unifiedStorage Storage interface for the current environment
* @param unifiedChainEvents On-chain event listener
* @param chain
* @param prices Swap pricing handler
* @param tokens
* @param versionedContracts
* @param lnApi
* @param lpApi
* @param options
* @param events Instance to use for emitting events
*/
constructor(chainIdentifier, unifiedStorage, unifiedChainEvents, chain, prices, tokens, versionedContracts, lnApi, lpApi, options, events) {
super(chainIdentifier, unifiedStorage, unifiedChainEvents, chain, prices, tokens, lpApi, options, versionedContracts, events);
this.lnApi = lnApi;
}
/**
* Generates a new 32-byte secret to be used as pre-image for lightning network invoice & HTLC swap
*
* @returns Hash pre-image & payment hash
*
* @internal
*/
getSecretAndHash() {
const secret = (0, Utils_1.randomBytes)(32);
const paymentHash = buffer_1.Buffer.from((0, sha256_1.sha256)(secret));
return { secret, paymentHash };
}
/**
* Pre-fetches intermediary's LN node capacity, doesn't throw, instead returns null
*
* @param pubkeyPromise Promise that resolves when we receive "lnPublicKey" param from the intermediary through
* streaming
*
* @returns LN Node liquidity
*
* @internal
*/
preFetchLnCapacity(pubkeyPromise) {
return pubkeyPromise.then(pubkey => {
if (pubkey == null)
return null;
return this.lnApi.getLNNodeLiquidity(pubkey);
}).catch(e => {
this.logger.warn("preFetchLnCapacity(): Error: ", e);
return null;
});
}
/**
* Verifies whether the intermediary's lightning node has enough inbound capacity to receive the LN payment
*
* @param lp Intermediary
* @param decodedPr Decoded bolt11 lightning network invoice
* @param lnCapacityPrefetchPromise Pre-fetch for LN node capacity, preFetchLnCapacity()
* @param abortSignal Abort signal
*
* @throws {IntermediaryError} if the lightning network node doesn't have enough inbound liquidity
* @throws {Error} if the lightning network node's inbound liquidity might be enough, but the swap would
* deplete more than half of the liquidity
*
* @internal
*/
async verifyLnNodeCapacity(lp, decodedPr, lnCapacityPrefetchPromise, abortSignal) {
if (decodedPr.payeeNodeKey == null)
throw new Error("Unable to extract payee pubkey from the swap invoice!");
if (decodedPr.millisatoshis == null)
throw new Error("Swap invoice doesn't contains msat amount field!");
const _result = await lnCapacityPrefetchPromise ?? await this.lnApi.getLNNodeLiquidity(decodedPr.payeeNodeKey);
if (_result === null)
throw new IntermediaryError_1.IntermediaryError("LP's lightning node not found in the lightning network graph!");
if (abortSignal != null)
abortSignal.throwIfAborted();
lp.lnData = _result;
if (decodedPr.payeeNodeKey !== _result.publicKey)
throw new IntermediaryError_1.IntermediaryError("Invalid pr returned - payee pubkey");
const amountIn = (BigInt(decodedPr.millisatoshis) + 999n) / 1000n;
if (_result.capacity < amountIn)
throw new IntermediaryError_1.IntermediaryError("LP's lightning node doesn't have enough inbound capacity for the swap!");
if ((_result.capacity / 2n) < amountIn)
throw new Error("LP's lightning node probably doesn't have enough inbound capacity for the swap!");
}
/**
* Parses and fetches lnurl withdraw params from the specified lnurl
*
* @param lnurl LNURL to be parsed and fetched
* @param abortSignal Abort signal
*
* @throws {UserError} if the LNURL is invalid or if it's not a LNURL-withdraw
*
* @internal
*/
async getLNURLWithdraw(lnurl, abortSignal) {
if (typeof (lnurl) !== "string")
return lnurl;
const res = await LNURL_1.LNURL.getLNURL(lnurl, true, this._options.getRequestTimeout, abortSignal);
if (res == null)
throw new UserError_1.UserError("Invalid LNURL");
if (res.tag !== "withdrawRequest")
throw new UserError_1.UserError("Not a LNURL-withdrawal");
return res;
}
/**
* Returns the swap expiry, leaving enough time for the user to claim the HTLC
*
* @param data Parsed swap data
*
* @internal
*/
_getHtlcTimeout(data) {
return data.getExpiry() - 600n;
}
}
exports.IFromBTCLNWrapper = IFromBTCLNWrapper;