UNPKG

@arkade-os/sdk

Version:

Bitcoin wallet SDK with Taproot and Ark integration

184 lines (183 loc) 7.73 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Batch = void 0; const ark_1 = require("../providers/ark"); const txTree_1 = require("../tree/txTree"); const base_1 = require("@scure/base"); /** * Batch namespace provides utilities for joining and processing batch session. * The batch settlement process involves multiple events, this namespace provides abstractions and types to handle them. * @see https://docs.arkadeos.com/learn/pillars/batch-swaps * @example * ```typescript * // use wallet handler or create a custom one * const handler = wallet.createBatchHandler(intentId, inputs, musig2session); * * const abortController = new AbortController(); * // Get event stream from Ark provider * const eventStream = arkProvider.getEventStream( * abortController.signal, * ['your-topic-1', 'your-topic-2'] * ); * * // Join the batch and process events * try { * const commitmentTxid = await Batch.join(eventStream, handler); * console.log('Batch completed with commitment:', commitmentTxid); * } catch (error) { * console.error('Batch processing failed:', error); * } finally { * abortController.abort(); * } * ``` */ var Batch; (function (Batch) { // State machine steps for batch session let Step; (function (Step) { Step["Start"] = "start"; Step["BatchStarted"] = "batch_started"; Step["TreeSigningStarted"] = "tree_signing_started"; Step["TreeNoncesAggregated"] = "tree_nonces_aggregated"; Step["BatchFinalization"] = "batch_finalization"; })(Step || (Step = {})); /** * Start the state machine that will process the batch events and join a batch. * @param eventIterator - The events stream to process. * @param handler - How to react to events. * @param options - Options. */ async function join(eventIterator, handler, options = {}) { const { abortController, skipVtxoTreeSigning = false, eventCallback, } = options; let step = Step.Start; // keep track of tree transactions as they arrive const flatVtxoTree = []; const flatConnectorTree = []; // once everything is collected, the TxTree objects are created let vtxoTree = undefined; let connectorTree = undefined; for await (const event of eventIterator) { if (abortController?.signal.aborted) { throw new Error("canceled"); } if (eventCallback) { // don't wait for the callback to complete and ignore errors eventCallback(event).catch(() => { }); } switch (event.type) { case ark_1.SettlementEventType.BatchStarted: { const e = event; const { skip } = await handler.onBatchStarted(e); if (!skip) { step = Step.BatchStarted; if (skipVtxoTreeSigning) { // skip TxTree events and musig2 signatures and nonces step = Step.TreeNoncesAggregated; } } continue; } case ark_1.SettlementEventType.BatchFinalized: { if (step !== Step.BatchFinalization) { continue; } if (handler.onBatchFinalized) { await handler.onBatchFinalized(event); } return event.commitmentTxid; } case ark_1.SettlementEventType.BatchFailed: { if (handler.onBatchFailed) { await handler.onBatchFailed(event); continue; } throw new Error(event.reason); } case ark_1.SettlementEventType.TreeTx: { if (step !== Step.BatchStarted && step !== Step.TreeNoncesAggregated) { continue; } // batchIndex 0 = vtxo tree, batchIndex 1 = connector tree if (event.batchIndex === 0) { flatVtxoTree.push(event.chunk); } else { flatConnectorTree.push(event.chunk); } if (handler.onTreeTxEvent) { await handler.onTreeTxEvent(event); } continue; } case ark_1.SettlementEventType.TreeSignature: { if (step !== Step.TreeNoncesAggregated) { continue; } if (!vtxoTree) { throw new Error("vtxo tree not initialized"); } // push signature to the vtxo tree const tapKeySig = base_1.hex.decode(event.signature); vtxoTree.update(event.txid, (tx) => { tx.updateInput(0, { tapKeySig, }); }); if (handler.onTreeSignatureEvent) { await handler.onTreeSignatureEvent(event); } continue; } case ark_1.SettlementEventType.TreeSigningStarted: { if (step !== Step.BatchStarted) { continue; } // create vtxo tree from collected chunks vtxoTree = txTree_1.TxTree.create(flatVtxoTree); const { skip } = await handler.onTreeSigningStarted(event, vtxoTree); if (!skip) { step = Step.TreeSigningStarted; } continue; } case ark_1.SettlementEventType.TreeNonces: { if (step !== Step.TreeSigningStarted) { continue; } const { fullySigned } = await handler.onTreeNonces(event); if (fullySigned) { step = Step.TreeNoncesAggregated; } continue; } case ark_1.SettlementEventType.BatchFinalization: { if (step !== Step.TreeNoncesAggregated) { continue; } // Build vtxo tree if it hasn't been built yet if (!vtxoTree && flatVtxoTree.length > 0) { vtxoTree = txTree_1.TxTree.create(flatVtxoTree); } if (!vtxoTree && !skipVtxoTreeSigning) { throw new Error("vtxo tree not initialized"); } // Build connector tree if we have chunks if (flatConnectorTree.length > 0) { connectorTree = txTree_1.TxTree.create(flatConnectorTree); } await handler.onBatchFinalization(event, vtxoTree, connectorTree); step = Step.BatchFinalization; continue; } default: // unknown event type, continue continue; } } // iterator closed without finalization, something went wrong throw new Error("event stream closed"); } Batch.join = join; })(Batch || (exports.Batch = Batch = {}));