UNPKG

kleros-escrow-data-service

Version:

Data service for interacting with Kleros Escrow

732 lines (731 loc) 39.3 kB
import { ethers } from "ethers"; import { BaseService } from "../base/BaseService"; import { Party } from "../types/transaction"; /** * Service for retrieving events from the Kleros Escrow contract */ export class EventService extends BaseService { /** * Creates a new EventService instance * @param config The Kleros Escrow configuration * @param provider Optional provider for read operations */ constructor(config, provider) { super(config, provider); } /** * Normalizes a block parameter to ensure it's in the correct format for ethers.js * @param blockParam The block parameter (number, string, or undefined) * @returns The normalized block parameter */ normalizeBlockParam(blockParam) { if (blockParam === undefined) { return undefined; } // Always convert to hex string if (typeof blockParam === "string" && blockParam.startsWith("0x")) { return blockParam; } const blockNumber = typeof blockParam === "string" ? parseInt(blockParam, 10) : blockParam; if (isNaN(blockNumber)) { console.warn(`Invalid block parameter: ${blockParam}, using undefined`); return undefined; } // Always return as hex string return ethers.utils.hexValue(blockNumber); } /** * Gets all events for a specific transaction * @param transactionId The ID of the transaction * @param options Optional filter options including fromBlock and toBlock * @returns All events related to the transaction */ async getEventsForTransaction(transactionId, options) { try { // Special case for known problematic transaction IDs if (transactionId === "89") { console.log("Using special handling for transaction ID 89"); // If no specific options provided, use extended search with no block range if (!(options === null || options === void 0 ? void 0 : options.fromBlock) && !(options === null || options === void 0 ? void 0 : options.toBlock)) { options = {}; // Ensure options is defined } } // Normalize block parameters let fromBlock = this.normalizeBlockParam(options === null || options === void 0 ? void 0 : options.fromBlock); let toBlock = this.normalizeBlockParam(options === null || options === void 0 ? void 0 : options.toBlock); // If toBlock is not provided, get the latest block if (toBlock === undefined) { try { const latestBlock = await this.provider.getBlock("latest"); toBlock = ethers.utils.hexValue(latestBlock.number); } catch (error) { console.warn("Error getting latest block, using a default range:", error); // If we can't get the latest block, use 'latest' toBlock = "latest"; } } console.log(`Searching for events from block ${fromBlock} to ${toBlock}`); const events = []; // Get all relevant event types with error handling let metaEvidenceEvents = []; let paymentEvents = []; let hasToPayFeeEvents = []; let disputeEvents = []; let evidenceEvents = []; let rulingEvents = []; try { // First try to get MetaEvidence events with the provided block range metaEvidenceEvents = await this.getMetaEvidenceEvents(transactionId, { fromBlock, toBlock, }); console.log(`Found ${metaEvidenceEvents.length} MetaEvidence events in initial search`); // If no MetaEvidence events found and no specific block range was provided, try extended search if (metaEvidenceEvents.length === 0 && !(options === null || options === void 0 ? void 0 : options.fromBlock) && !(options === null || options === void 0 ? void 0 : options.toBlock)) { try { console.log("No MetaEvidence events found in initial search. Starting extended search."); metaEvidenceEvents = await this.getMetaEvidenceEventsExtended(transactionId); console.log(`Found ${metaEvidenceEvents.length} MetaEvidence events after extended search`); // If we found events in extended search, update fromBlock and toBlock for other event types if (metaEvidenceEvents.length > 0) { // Find the earliest block where we found a MetaEvidence event const earliestBlock = Math.min(...metaEvidenceEvents.map((e) => e.blockNumber)); // Update fromBlock to start from this block (or earlier) if (earliestBlock > 0) { fromBlock = ethers.utils.hexValue(Math.max(1, earliestBlock - 1000)); console.log(`Updating fromBlock to ${fromBlock} based on found MetaEvidence event`); } } } catch (error) { console.warn("Error in extended MetaEvidence search:", error); } } } catch (error) { console.warn("Error fetching MetaEvidence events:", error); metaEvidenceEvents = []; } try { paymentEvents = await this.getPaymentEvents(transactionId, { fromBlock, toBlock, }); console.log(`Found ${paymentEvents.length} Payment events`); } catch (error) { console.warn("Error fetching Payment events:", error); paymentEvents = []; } try { hasToPayFeeEvents = await this.getHasToPayFeeEvents(transactionId, { fromBlock, toBlock, }); console.log(`Found ${hasToPayFeeEvents.length} HasToPayFee events`); } catch (error) { console.warn("Error fetching HasToPayFee events:", error); hasToPayFeeEvents = []; } try { disputeEvents = await this.getDisputeEvents(transactionId, { fromBlock, toBlock, }); console.log(`Found ${disputeEvents.length} Dispute events`); } catch (error) { console.warn("Error fetching Dispute events:", error); disputeEvents = []; } try { evidenceEvents = await this.getEvidenceEvents(transactionId, { fromBlock, toBlock, }); console.log(`Found ${evidenceEvents.length} Evidence events`); } catch (error) { console.warn("Error fetching Evidence events:", error); evidenceEvents = []; } try { rulingEvents = await this.getRulingEvents(transactionId, { fromBlock, toBlock, }); console.log(`Found ${rulingEvents.length} Ruling events`); } catch (error) { console.warn("Error fetching Ruling events:", error); rulingEvents = []; } // Ensure all event arrays are valid before combining const allEvents = [ ...(Array.isArray(metaEvidenceEvents) ? metaEvidenceEvents : []), ...(Array.isArray(paymentEvents) ? paymentEvents : []), ...(Array.isArray(hasToPayFeeEvents) ? hasToPayFeeEvents : []), ...(Array.isArray(disputeEvents) ? disputeEvents : []), ...(Array.isArray(evidenceEvents) ? evidenceEvents : []), ...(Array.isArray(rulingEvents) ? rulingEvents : []), ]; // Sort events by block number if they have one return allEvents .filter((event) => event && typeof event.blockNumber === "number") .sort((a, b) => a.blockNumber - b.blockNumber); } catch (error) { console.error("Error in getEventsForTransaction:", error); return []; } } /** * Gets transaction creation events * @param options Optional filter options including fromBlock and toBlock * @returns An array of transaction creation events */ async getTransactionCreationEvents(options) { try { const fromBlock = this.normalizeBlockParam(options === null || options === void 0 ? void 0 : options.fromBlock); const toBlock = this.normalizeBlockParam(options === null || options === void 0 ? void 0 : options.toBlock); const filter = this.escrowContract.filters.TransactionCreated(); return await this.escrowContract.queryFilter(filter, fromBlock, toBlock); } catch (error) { console.error("Error in getTransactionCreationEvents:", error); return []; } } /** * Gets MetaEvidence events for a transaction with extended search capability * @param transactionId The ID of the transaction * @param options Optional filter options including fromBlock and toBlock * @returns Array of MetaEvidence events */ async getMetaEvidenceEvents(transactionId, options) { try { const fromBlock = this.normalizeBlockParam(options === null || options === void 0 ? void 0 : options.fromBlock); const toBlock = this.normalizeBlockParam(options === null || options === void 0 ? void 0 : options.toBlock); console.log(`Getting MetaEvidence events with fromBlock=${fromBlock}, toBlock=${toBlock}`); // Always use an unfiltered query and filter manually afterward console.log(`Using unfiltered MetaEvidence query for ID: ${transactionId}`); const filter = this.escrowContract.filters.MetaEvidence(); const events = await this.escrowContract.queryFilter(filter, fromBlock, toBlock); // Filter the results manually to get only events for this transaction ID const relevantEvents = events.filter((event) => { var _a; try { const eventMetaEvidenceId = (_a = event.args) === null || _a === void 0 ? void 0 : _a._metaEvidenceID.toString(); return eventMetaEvidenceId === transactionId; } catch (error) { console.warn(`Error comparing event metaEvidenceID:`, error); return false; } }); console.log(`Found ${relevantEvents.length} MetaEvidence events for transaction ${transactionId}`); // If we found events, process them and return if (relevantEvents.length > 0) { return await this.processMetaEvidenceEvents(relevantEvents, transactionId); } // If no events found and no specific block range was provided, try extended search if (relevantEvents.length === 0 && !(options === null || options === void 0 ? void 0 : options.fromBlock) && !(options === null || options === void 0 ? void 0 : options.toBlock)) { console.log(`No MetaEvidence events found in initial search. Starting extended search for transaction ${transactionId}`); return await this.getMetaEvidenceEventsExtended(transactionId); } // If specific block range was provided but no events found, return empty array return []; } catch (error) { console.error("Error in getMetaEvidenceEvents:", error); return []; // Return empty array instead of throwing to improve reliability } } /** * Extended search for MetaEvidence events * Searches multiple block ranges until it finds at least one matching event * @param transactionId The ID of the transaction * @returns Array of MetaEvidence events */ async getMetaEvidenceEventsExtended(transactionId) { try { // Step 1: Get transaction details to find lastInteraction timestamp console.log(`Getting transaction ${transactionId} details for extended search`); const transaction = await this.escrowContract.transactions(transactionId); const lastInteractionTimestamp = transaction.lastInteraction.toNumber(); console.log(`Transaction ${transactionId} lastInteraction timestamp: ${lastInteractionTimestamp}`); // Step 2: Get current block and timestamp const currentBlock = await this.provider.getBlockNumber(); const currentBlockDetails = await this.provider.getBlock(currentBlock); const currentTimestamp = currentBlockDetails.timestamp; // Step 3: Calculate approximate block for lastInteraction const AVERAGE_BLOCK_TIME = 13; // seconds const secondsDifference = currentTimestamp - lastInteractionTimestamp; const estimatedBlocksBack = Math.floor(secondsDifference / AVERAGE_BLOCK_TIME); const estimatedLastInteractionBlock = currentBlock - estimatedBlocksBack; console.log(`Current block: ${currentBlock}, timestamp: ${currentTimestamp}`); console.log(`Estimated blocks back: ${estimatedBlocksBack}`); console.log(`Estimated block for lastInteraction: ${estimatedLastInteractionBlock}`); // Step 4: Set initial search range (10,000 blocks before estimated block) let fromBlock = Math.max(1, estimatedLastInteractionBlock - 10000); let toBlock = estimatedLastInteractionBlock + 100; // Add small buffer console.log(`Initial extended search range: ${fromBlock} to ${toBlock}`); // Try initial range let events = await this.searchMetaEvidenceInRange(transactionId, fromBlock, toBlock); // If events found, return them if (events.length > 0) { console.log(`Found ${events.length} MetaEvidence events in initial extended search`); return events; } // Step 5: If no events found, try up to 10 additional ranges of 10,000 blocks each for (let i = 1; i <= 10; i++) { const extendedFromBlock = Math.max(1, fromBlock - i * 10000); const extendedToBlock = fromBlock - (i - 1) * 10000 - 1; console.log(`Extended search ${i}: From block ${extendedFromBlock} to ${extendedToBlock}`); events = await this.searchMetaEvidenceInRange(transactionId, extendedFromBlock, extendedToBlock); // If events found, stop searching and return if (events.length > 0) { console.log(`Found ${events.length} MetaEvidence events in extended search ${i}`); return events; } } // If no events found after all attempts, return empty array console.log(`No MetaEvidence events found after extended search for transaction ${transactionId}`); return []; } catch (error) { console.error("Error in getMetaEvidenceEventsExtended:", error); return []; // Return empty array instead of throwing } } /** * Helper method to search for MetaEvidence events in a specific block range * @param transactionId The ID of the transaction * @param fromBlock The starting block number * @param toBlock The ending block number * @returns Array of MetaEvidence events */ async searchMetaEvidenceInRange(transactionId, fromBlock, toBlock) { try { // Convert block numbers to hex strings const fromBlockHex = ethers.utils.hexValue(fromBlock); const toBlockHex = ethers.utils.hexValue(toBlock); console.log(`Searching for MetaEvidence events in range: ${fromBlock} to ${toBlock}`); // Use unfiltered query const filter = this.escrowContract.filters.MetaEvidence(); const events = await this.escrowContract.queryFilter(filter, fromBlockHex, toBlockHex); // Filter manually for this transaction ID const relevantEvents = events.filter((event) => { var _a; try { const eventMetaEvidenceId = (_a = event.args) === null || _a === void 0 ? void 0 : _a._metaEvidenceID.toString(); return eventMetaEvidenceId === transactionId; } catch (error) { return false; } }); console.log(`Found ${relevantEvents.length} matching events in range ${fromBlock} to ${toBlock}`); // Process events if any found if (relevantEvents.length > 0) { return await this.processMetaEvidenceEvents(relevantEvents, transactionId); } return []; } catch (error) { console.warn(`Error searching MetaEvidence in range ${fromBlock}-${toBlock}:`, error); return []; // Return empty array instead of throwing } } /** * Process raw MetaEvidence events into structured format * @param events Raw ethers.js events * @param transactionId The transaction ID * @returns Processed MetaEvidence events */ async processMetaEvidenceEvents(events, transactionId) { var _a, _b, _c, _d; const results = []; for (const event of events) { try { const block = await event.getBlock(); results.push({ transactionId, blockNumber: event.blockNumber, transactionHash: event.transactionHash, timestamp: block.timestamp, metaEvidenceId: (_a = event.args) === null || _a === void 0 ? void 0 : _a._metaEvidenceID.toString(), evidence: (_b = event.args) === null || _b === void 0 ? void 0 : _b._evidence, }); } catch (error) { console.warn(`Error processing MetaEvidence event at block ${event.blockNumber}:`, error); // Add with minimal information results.push({ transactionId, blockNumber: event.blockNumber, transactionHash: event.transactionHash, timestamp: 0, // Unknown timestamp metaEvidenceId: (_c = event.args) === null || _c === void 0 ? void 0 : _c._metaEvidenceID.toString(), evidence: (_d = event.args) === null || _d === void 0 ? void 0 : _d._evidence, }); } } return results; } /** * Gets payment events * @param transactionId The ID of the transaction * @param options Optional filter options including fromBlock and toBlock * @returns An array of payment events */ async getPaymentEvents(transactionId, options) { var _a, _b, _c, _d, _e, _f; try { const fromBlock = this.normalizeBlockParam(options === null || options === void 0 ? void 0 : options.fromBlock); const toBlock = this.normalizeBlockParam(options === null || options === void 0 ? void 0 : options.toBlock); console.log(`Getting Payment events with fromBlock=${fromBlock}, toBlock=${toBlock}`); // Always use an unfiltered query and filter manually afterward console.log(`Using unfiltered Payment query for ID: ${transactionId || "all"}`); const filter = this.escrowContract.filters.Payment(); const events = await this.escrowContract.queryFilter(filter, fromBlock, toBlock); // Filter the results manually to get only events for this transaction ID const relevantEvents = transactionId ? events.filter((event) => { var _a; try { const eventTransactionId = (_a = event.args) === null || _a === void 0 ? void 0 : _a._transactionID.toString(); return eventTransactionId === transactionId; } catch (error) { console.warn(`Error comparing event transactionID:`, error); return false; } }) : events; console.log(`Found ${relevantEvents.length} Payment events for transaction ${transactionId || "all"}`); const results = []; for (const event of relevantEvents) { try { const block = await event.getBlock(); results.push({ transactionId: (_a = event.args) === null || _a === void 0 ? void 0 : _a._transactionID.toString(), blockNumber: event.blockNumber, transactionHash: event.transactionHash, timestamp: block.timestamp, amount: (_b = event.args) === null || _b === void 0 ? void 0 : _b._amount.toString(), party: (_c = event.args) === null || _c === void 0 ? void 0 : _c._party, }); } catch (error) { console.warn(`Error processing Payment event at block ${event.blockNumber}:`, error); // Add the event with minimal information results.push({ transactionId: (_d = event.args) === null || _d === void 0 ? void 0 : _d._transactionID.toString(), blockNumber: event.blockNumber, transactionHash: event.transactionHash, timestamp: 0, // Unknown timestamp amount: (_e = event.args) === null || _e === void 0 ? void 0 : _e._amount.toString(), party: (_f = event.args) === null || _f === void 0 ? void 0 : _f._party, }); } } return results; } catch (error) { console.error("Error in getPaymentEvents:", error); return []; // Return empty array instead of throwing } } /** * Gets HasToPayFee events for a transaction * @param transactionId The ID of the transaction * @param options Optional filter options including fromBlock and toBlock * @returns Array of HasToPayFee events */ async getHasToPayFeeEvents(transactionId, options) { var _a, _b, _c, _d; try { const fromBlock = this.normalizeBlockParam(options === null || options === void 0 ? void 0 : options.fromBlock); const toBlock = this.normalizeBlockParam(options === null || options === void 0 ? void 0 : options.toBlock); console.log(`Getting HasToPayFee events with fromBlock=${fromBlock}, toBlock=${toBlock}`); // Always use an unfiltered query and filter manually afterward console.log(`Using unfiltered HasToPayFee query for ID: ${transactionId || "all"}`); const filter = this.escrowContract.filters.HasToPayFee(); const events = await this.escrowContract.queryFilter(filter, fromBlock, toBlock); // Filter the results manually to get only events for this transaction ID const relevantEvents = transactionId ? events.filter((event) => { var _a; try { const eventTransactionId = (_a = event.args) === null || _a === void 0 ? void 0 : _a._transactionID.toString(); return eventTransactionId === transactionId; } catch (error) { console.warn(`Error comparing event transactionID:`, error); return false; } }) : events; console.log(`Found ${relevantEvents.length} HasToPayFee events for transaction ${transactionId || "all"}`); const results = []; for (const event of relevantEvents) { try { const block = await event.getBlock(); results.push({ transactionId: (_a = event.args) === null || _a === void 0 ? void 0 : _a._transactionID.toString(), blockNumber: event.blockNumber, transactionHash: event.transactionHash, timestamp: block.timestamp, party: ((_b = event.args) === null || _b === void 0 ? void 0 : _b._party) === 0 ? Party.Sender : Party.Receiver, }); } catch (error) { console.warn(`Error processing HasToPayFee event at block ${event.blockNumber}:`, error); // Add the event with minimal information results.push({ transactionId: (_c = event.args) === null || _c === void 0 ? void 0 : _c._transactionID.toString(), blockNumber: event.blockNumber, transactionHash: event.transactionHash, timestamp: 0, // Unknown timestamp party: ((_d = event.args) === null || _d === void 0 ? void 0 : _d._party) === 0 ? Party.Sender : Party.Receiver, }); } } return results; } catch (error) { console.error("Error in getHasToPayFeeEvents:", error); return []; // Return empty array instead of throwing } } /** * Gets dispute creation events * @param transactionId The ID of the transaction * @param options Optional filter options including fromBlock and toBlock * @returns An array of dispute creation events */ async getDisputeEvents(transactionId, options) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; try { const fromBlock = this.normalizeBlockParam(options === null || options === void 0 ? void 0 : options.fromBlock); const toBlock = this.normalizeBlockParam(options === null || options === void 0 ? void 0 : options.toBlock); console.log(`Getting Dispute events with fromBlock=${fromBlock}, toBlock=${toBlock}`); // Always use an unfiltered query and filter manually afterward console.log(`Using unfiltered Dispute query for ID: ${transactionId || "all"}`); const filter = this.escrowContract.filters.Dispute(); const events = await this.escrowContract.queryFilter(filter, fromBlock, toBlock); // If transactionId is provided, filter events by metaEvidenceID const relevantEvents = transactionId ? events.filter((event) => { var _a; try { const eventMetaEvidenceId = (_a = event.args) === null || _a === void 0 ? void 0 : _a._metaEvidenceID.toString(); return eventMetaEvidenceId === transactionId; } catch (error) { console.warn(`Error comparing event metaEvidenceID:`, error); return false; } }) : events; console.log(`Found ${relevantEvents.length} Dispute events for transaction ${transactionId || "all"}`); const results = []; for (const event of relevantEvents) { try { const block = await event.getBlock(); results.push({ transactionId: (_a = event.args) === null || _a === void 0 ? void 0 : _a._metaEvidenceID.toString(), blockNumber: event.blockNumber, transactionHash: event.transactionHash, timestamp: block.timestamp, disputeId: (_b = event.args) === null || _b === void 0 ? void 0 : _b._disputeID.toNumber(), arbitrator: (_c = event.args) === null || _c === void 0 ? void 0 : _c._arbitrator, metaEvidenceId: (_d = event.args) === null || _d === void 0 ? void 0 : _d._metaEvidenceID.toString(), evidenceGroupId: (_e = event.args) === null || _e === void 0 ? void 0 : _e._evidenceGroupID.toString(), }); } catch (error) { console.warn(`Error processing Dispute event at block ${event.blockNumber}:`, error); // Add the event with minimal information results.push({ transactionId: (_f = event.args) === null || _f === void 0 ? void 0 : _f._metaEvidenceID.toString(), blockNumber: event.blockNumber, transactionHash: event.transactionHash, timestamp: 0, // Unknown timestamp disputeId: (_g = event.args) === null || _g === void 0 ? void 0 : _g._disputeID.toNumber(), arbitrator: (_h = event.args) === null || _h === void 0 ? void 0 : _h._arbitrator, metaEvidenceId: (_j = event.args) === null || _j === void 0 ? void 0 : _j._metaEvidenceID.toString(), evidenceGroupId: (_k = event.args) === null || _k === void 0 ? void 0 : _k._evidenceGroupID.toString(), }); } } return results; } catch (error) { console.error("Error in getDisputeEvents:", error); return []; // Return empty array instead of throwing } } /** * Gets evidence submission events * @param transactionId The ID of the transaction * @param options Optional filter options including fromBlock and toBlock * @returns An array of evidence submission events */ async getEvidenceEvents(transactionId, options) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; try { const fromBlock = this.normalizeBlockParam(options === null || options === void 0 ? void 0 : options.fromBlock); const toBlock = this.normalizeBlockParam(options === null || options === void 0 ? void 0 : options.toBlock); console.log(`Getting Evidence events with fromBlock=${fromBlock}, toBlock=${toBlock}`); // Always use an unfiltered query and filter manually afterward console.log(`Using unfiltered Evidence query for ID: ${transactionId || "all"}`); const filter = this.escrowContract.filters.Evidence(); const events = await this.escrowContract.queryFilter(filter, fromBlock, toBlock); // If transactionId is provided, filter events by evidenceGroupID const relevantEvents = transactionId ? events.filter((event) => { var _a; try { const eventGroupId = (_a = event.args) === null || _a === void 0 ? void 0 : _a._evidenceGroupID.toString(); return eventGroupId === transactionId; } catch (error) { console.warn(`Error comparing event group ID:`, error); return false; } }) : events; console.log(`Found ${relevantEvents.length} Evidence events for transaction ${transactionId || "all"}`); const results = []; for (const event of relevantEvents) { try { const block = await event.getBlock(); results.push({ transactionId: (_a = event.args) === null || _a === void 0 ? void 0 : _a._evidenceGroupID.toString(), blockNumber: event.blockNumber, transactionHash: event.transactionHash, timestamp: block.timestamp, party: (_b = event.args) === null || _b === void 0 ? void 0 : _b._party, evidence: (_c = event.args) === null || _c === void 0 ? void 0 : _c._evidence, arbitrator: (_d = event.args) === null || _d === void 0 ? void 0 : _d._arbitrator, evidenceGroupId: (_e = event.args) === null || _e === void 0 ? void 0 : _e._evidenceGroupID.toString(), }); } catch (error) { console.warn(`Error processing Evidence event at block ${event.blockNumber}:`, error); // Add the event with minimal information results.push({ transactionId: (_f = event.args) === null || _f === void 0 ? void 0 : _f._evidenceGroupID.toString(), blockNumber: event.blockNumber, transactionHash: event.transactionHash, timestamp: 0, // Unknown timestamp party: (_g = event.args) === null || _g === void 0 ? void 0 : _g._party, evidence: (_h = event.args) === null || _h === void 0 ? void 0 : _h._evidence, arbitrator: (_j = event.args) === null || _j === void 0 ? void 0 : _j._arbitrator, evidenceGroupId: (_k = event.args) === null || _k === void 0 ? void 0 : _k._evidenceGroupID.toString(), }); } } return results; } catch (error) { console.error("Error in getEvidenceEvents:", error); return []; // Return empty array instead of throwing } } /** * Gets ruling events * @param transactionId The ID of the transaction * @param options Optional filter options including fromBlock and toBlock * @returns An array of ruling events */ async getRulingEvents(transactionId, options) { var _a, _b, _c, _d, _e, _f, _g; try { const fromBlock = this.normalizeBlockParam(options === null || options === void 0 ? void 0 : options.fromBlock); const toBlock = this.normalizeBlockParam(options === null || options === void 0 ? void 0 : options.toBlock); console.log(`Getting Ruling events with fromBlock=${fromBlock}, toBlock=${toBlock}`); let disputeId; // If transactionId is provided, get the disputeId if (transactionId) { try { const tx = await this.escrowContract.transactions(transactionId); disputeId = tx.disputeId.toNumber(); if (disputeId === 0) { return []; } } catch (error) { console.warn(`Error getting transaction ${transactionId} for dispute ID:`, error); return []; } } const filter = this.escrowContract.filters.Ruling(null, disputeId); const events = await this.escrowContract.queryFilter(filter, fromBlock, toBlock); const results = []; for (const event of events) { try { const block = await event.getBlock(); // If we don't have a transactionId, we need to find it let txId = transactionId; if (!txId) { try { // This is a simplified approach - in a real implementation, you might want to use a more efficient method // Limit the search to a reasonable number to prevent timeouts const MAX_TX_TO_CHECK = 100; const count = await this.escrowContract.getCountTransactions(); const txCount = Math.min(count.toNumber(), MAX_TX_TO_CHECK); for (let i = 0; i < txCount; i++) { const tx = await this.escrowContract.transactions(i); if (tx.disputeId.eq((_a = event.args) === null || _a === void 0 ? void 0 : _a._disputeID)) { txId = i.toString(); break; } } } catch (error) { console.error("Error finding transaction ID for dispute:", error); txId = "unknown"; } } results.push({ transactionId: txId || "unknown", blockNumber: event.blockNumber, transactionHash: event.transactionHash, timestamp: block.timestamp, disputeId: (_b = event.args) === null || _b === void 0 ? void 0 : _b._disputeID.toNumber(), ruling: (_c = event.args) === null || _c === void 0 ? void 0 : _c._ruling.toNumber(), arbitrator: (_d = event.args) === null || _d === void 0 ? void 0 : _d._arbitrator, }); } catch (error) { console.warn(`Error processing Ruling event at block ${event.blockNumber}:`, error); // Add the event with minimal information results.push({ transactionId: transactionId || "unknown", blockNumber: event.blockNumber, transactionHash: event.transactionHash, timestamp: 0, // Unknown timestamp disputeId: (_e = event.args) === null || _e === void 0 ? void 0 : _e._disputeID.toNumber(), ruling: (_f = event.args) === null || _f === void 0 ? void 0 : _f._ruling.toNumber(), arbitrator: (_g = event.args) === null || _g === void 0 ? void 0 : _g._arbitrator, }); } } return results; } catch (error) { console.error("Error in getRulingEvents:", error); return []; // Return empty array instead of throwing } } }