@atomiqlabs/sdk
Version:
atomiq labs SDK for cross-chain swaps between smart chains and bitcoin
168 lines (167 loc) • 7.34 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.IEscrowSwapWrapper = void 0;
const ISwapWrapper_1 = require("../ISwapWrapper");
const base_1 = require("@atomiqlabs/base");
/**
* Base class for wrappers of escrow-based swaps (i.e. swaps utilizing PrTLC and HTLC primitives)
*
* @category Swaps/Abstract
*/
class IEscrowSwapWrapper extends ISwapWrapper_1.ISwapWrapper {
constructor(chainIdentifier, unifiedStorage, unifiedChainEvents, chain, prices, tokens, lpApi, options, versionedContracts, events) {
super(chainIdentifier, unifiedStorage, unifiedChainEvents, chain, prices, tokens, lpApi, options, events);
/**
* @internal
*/
this._contract = (version) => {
const _version = version ?? "v1";
const data = this._versionedContracts[_version];
if (data == null)
throw new Error(`Invalid contract version ${_version} requested`);
return data.swapContract;
};
/**
* @internal
*/
this._swapDataDeserializer = (version) => {
const _version = version ?? "v1";
const data = this._versionedContracts[_version];
if (data == null)
throw new Error(`Invalid contract version ${_version} requested`);
return data.swapDataConstructor;
};
//TODO: Properly populate in constructor
this._versionedContracts = {};
this._versionedContracts = versionedContracts;
}
/**
* Pre-fetches signature verification data from the server's pre-sent promise, doesn't throw, instead returns null
*
* @param signDataPrefetch Promise that resolves when we receive "signDataPrefetch" from the LP in streaming mode
* @param contractVersion
* @returns Pre-fetched signature verification data or null if failed
*
* @internal
*/
preFetchSignData(signDataPrefetch, contractVersion) {
if (this._contract(contractVersion).preFetchForInitSignatureVerification == null) {
// Catch promise rejections, should they happen
signDataPrefetch.catch(() => { });
return Promise.resolve(undefined);
}
return signDataPrefetch.then(obj => {
if (obj == null)
return undefined;
return this._contract(contractVersion).preFetchForInitSignatureVerification(obj);
}).catch(e => {
this.logger.error("preFetchSignData(): Error: ", e);
});
}
/**
* Verifies swap initialization signature returned by the intermediary
*
* @param initiator A smart chain account initiating the swap
* @param data Parsed swap data from the intermediary
* @param signature Response of the intermediary
* @param feeRatePromise Pre-fetched fee rate promise
* @param preFetchSignatureVerificationData Pre-fetched signature verification data
* @param contractVersion
* @param abortSignal
* @returns Swap initialization signature expiry
* @throws {SignatureVerificationError} when swap init signature is invalid
*
* @internal
*/
async verifyReturnedSignature(initiator, data, signature, feeRatePromise, preFetchSignatureVerificationData, contractVersion, abortSignal) {
const [feeRate, preFetchedSignatureData] = await Promise.all([feeRatePromise, preFetchSignatureVerificationData]);
await this._contract(contractVersion).isValidInitAuthorization(initiator, data, signature, feeRate, preFetchedSignatureData);
return await this._contract(contractVersion).getInitAuthorizationExpiry(data, signature, preFetchedSignatureData);
}
/**
* Processes a single SC on-chain event
* @param event
* @param swap
*
* @internal
*/
async processEvent(event, swap) {
if (swap == null)
return;
let swapChanged = false;
if (event instanceof base_1.InitializeEvent) {
swapChanged = await this.processEventInitialize(swap, event);
if (event.meta?.txId != null && swap._commitTxId !== event.meta.txId) {
swap._commitTxId = event.meta.txId;
swapChanged ||= true;
}
}
if (event instanceof base_1.ClaimEvent) {
swapChanged = await this.processEventClaim(swap, event);
if (event.meta?.txId != null && swap._claimTxId !== event.meta.txId) {
swap._claimTxId = event.meta.txId;
swapChanged ||= true;
}
}
if (event instanceof base_1.RefundEvent) {
swapChanged = await this.processEventRefund(swap, event);
if (event.meta?.txId != null && swap._refundTxId !== event.meta.txId) {
swap._refundTxId = event.meta.txId;
swapChanged ||= true;
}
}
this.logger.info("processEvents(): " + event.constructor.name + " processed for " + swap.getId() + " swap: ", swap);
if (swapChanged) {
await swap._saveAndEmit();
}
}
/**
* @inheritDoc
* @internal
*/
async _checkPastSwaps(pastSwaps) {
const changedSwaps = [];
const removeSwaps = [];
const swapExpiredStatus = {};
const checkStatusSwaps = {};
for (let pastSwap of pastSwaps) {
if (pastSwap._shouldFetchExpiryStatus()) {
//Check expiry
swapExpiredStatus[pastSwap.getId()] = await pastSwap._verifyQuoteDefinitelyExpired();
}
if (pastSwap._shouldFetchOnchainState()) {
//Add to swaps for which status should be checked
if (pastSwap._data != null)
(checkStatusSwaps[pastSwap._contractVersion ?? "v1"] ??= []).push(pastSwap);
}
}
for (let version in checkStatusSwaps) {
if (this._versionedContracts[version] == null) {
this.logger.warn(`_checkPastSwaps(): No contract was found for ${this.chainIdentifier} version ${version}! Skipping these swaps!`);
continue;
}
const _checkStatusSwap = checkStatusSwaps[version];
const swapStatuses = await this._contract(version).getCommitStatuses(_checkStatusSwap.map(val => ({
signer: val._getInitiator(),
swapData: val._data
})));
for (let pastSwap of _checkStatusSwap) {
const escrowHash = pastSwap.getEscrowHash();
const shouldSave = await pastSwap._sync(false, swapExpiredStatus[pastSwap.getId()], escrowHash == null ? undefined : swapStatuses[escrowHash]);
if (shouldSave) {
if (pastSwap.isQuoteExpired()) {
removeSwaps.push(pastSwap);
}
else {
changedSwaps.push(pastSwap);
}
}
}
}
return {
changedSwaps,
removeSwaps
};
}
}
exports.IEscrowSwapWrapper = IEscrowSwapWrapper;