zkverifyjs
Version:
Submit proofs to zkVerify and query proof state with ease using our npm package.
135 lines (134 loc) • 6.07 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.EventManager = void 0;
const aggregation_1 = require("../../../api/aggregation");
const events_1 = require("events");
const enums_1 = require("../../../enums");
class EventManager {
constructor(connectionManager) {
this.connectionManager = connectionManager;
this.emitter = new events_1.EventEmitter();
}
/**
* Subscribes to specified ZkVerifyEvents.
* For `NewAggregationReceipt`, `options` can include `domainId` and `aggregationId`.
* For runtime events (e.g., ProofVerified), options are ignored.
*
* @param subscriptions - List of events to subscribe to with optional callback and filtering options.
* @returns EventEmitter to allow listening to additional internal events (e.g., `Unsubscribe`).
*/
subscribe(subscriptions) {
const { api } = this.connectionManager;
const eventsToSubscribe = subscriptions?.length
? subscriptions
: enums_1.PUBLIC_ZK_VERIFY_EVENTS.map((event) => ({
event,
callback: undefined,
options: event === enums_1.ZkVerifyEvents.NewAggregationReceipt
? undefined
: undefined,
}));
eventsToSubscribe.forEach(({ event, callback, options }) => {
switch (event) {
case enums_1.ZkVerifyEvents.NewAggregationReceipt:
(0, aggregation_1.subscribeToNewAggregationReceipts)(api, (data) => {
this.emitter.emit(event, data);
if (callback)
callback(data);
}, options, this.emitter);
break;
case enums_1.ZkVerifyEvents.ProofVerified:
case enums_1.ZkVerifyEvents.NewProof:
case enums_1.ZkVerifyEvents.VkRegistered:
case enums_1.ZkVerifyEvents.NewDomain:
case enums_1.ZkVerifyEvents.DomainStateChanged:
case enums_1.ZkVerifyEvents.AggregationComplete:
this._subscribeToRuntimeEvent(api, event, callback);
break;
default:
throw new Error(`Unsupported event type for subscription: ${event}`);
}
});
return this.emitter;
}
/**
* Subscribes to on-chain runtime events using api.query.system.events
*/
_subscribeToRuntimeEvent(api, eventType, callback) {
api.query.system
.events((records) => {
for (const { event, phase } of records) {
const key = `${event.section}::${event.method}`;
const matchMap = {
[enums_1.ZkVerifyEvents.ProofVerified]: /::ProofVerified/,
[enums_1.ZkVerifyEvents.CannotAggregate]: 'aggregate::CannotAggregate',
[enums_1.ZkVerifyEvents.NewProof]: 'aggregate::NewProof',
[enums_1.ZkVerifyEvents.VkRegistered]: /::VkRegistered/,
[enums_1.ZkVerifyEvents.AggregationComplete]: 'aggregate::AggregationComplete',
[enums_1.ZkVerifyEvents.NewDomain]: 'aggregate::NewDomain',
[enums_1.ZkVerifyEvents.DomainStateChanged]: 'aggregate::DomainStateChanged',
};
const expected = matchMap[eventType];
if (expected &&
((typeof expected === 'string' && key === expected) ||
(expected instanceof RegExp && expected.test(key)))) {
const parsedPhase = phase.toJSON
? phase.toJSON()
: phase.toString();
const eventPayload = {
event: eventType,
data: event.data.toHuman?.() ?? event.data.toString(),
phase: parsedPhase,
};
this.emitter.emit(eventType, eventPayload);
if (callback) {
callback(eventPayload);
}
}
}
})
.catch((error) => {
this.emitter.emit(enums_1.ZkVerifyEvents.ErrorEvent, error);
});
}
/**
* Waits for a specific `NewAggregationReceipt` event and returns the result as a NewAggregationReceipt object.
*
* @param domainId - The domain ID to listen for.
* @param aggregationId - The aggregation ID to listen for.
* @param timeout - Optional timeout value in milliseconds.
* @returns {Promise<NewAggregationReceipt>} Resolves with the event data when found, or rejects on timeout/error.
*/
async waitForAggregationReceipt(domainId, aggregationId, timeout) {
const { api } = this.connectionManager;
const options = { domainId, aggregationId, timeout };
return new Promise((resolve, reject) => {
(0, aggregation_1.subscribeToNewAggregationReceipts)(api, (eventObject) => {
const event = eventObject;
if (event &&
event.data &&
event.data.domainId &&
event.data.aggregationId &&
event.data.receipt) {
const result = {
blockHash: event.blockHash ?? null,
domainId: Number(event.data.domainId),
aggregationId: Number(event.data.aggregationId),
receipt: String(event.data.receipt),
};
resolve(result);
}
else {
reject(new Error('Invalid event data structure'));
}
}, options, this.emitter).catch(reject);
});
}
/**
* Unsubscribes from all active subscriptions.
*/
unsubscribe() {
(0, aggregation_1.unsubscribe)(this.emitter);
}
}
exports.EventManager = EventManager;