import type { Result } from '@ethersproject/abi'; import type { BlockTag } from '@ethersproject/abstract-provider'; import { type providers, type EventFilter, type BaseContract } from 'ethers'; import { type SignerOrProvider } from '@colony/core'; import { type IpfsAdapter, type MetadataTypeMap, IpfsMetadata, type MetadataType } from './ipfs/index.js'; import type { Ethers6Filter } from './types.js'; /** * A valid eventsource (currently just an ethers.js {@link BaseContract}) */ export type EventSource = BaseContract; interface ContractFactory { connect(address: string, signerOrProvider: SignerOrProvider): T; } /** A Colony extended ethers Filter to keep track of where events are coming from */ export interface ColonyFilter extends Ethers6Filter { /** The generated id of the contract the event originated from */ eventSource: EventSource; /** The full event signature of this event (e.g. `TokenMinted(uint256))` */ eventName: string; } /** A Colony specific topic that keeps track of which contract it belongs to */ export interface ColonyTopic { /** The generated id of the contract the event originated from */ eventSource: EventSource; /** The full event signature of this event (e.g. `TokenMinted(uint256))` */ eventName: string; /** The encoded topic */ topic: string; } /** ColonyFilter with support for multi-events * For the multi-event compatible filters the following assumptions prevail: * - `address` is a mandatory field * - The list of filter topics is always OR'd, never AND'd. * - `fromBlock` and `toBlock` are not available */ export interface ColonyMultiFilter { address?: string; colonyTopics: ColonyTopic[]; } /** An Event that came from a contract within the Colony Network */ export interface ColonyEvent extends ColonyFilter { data: Result; transactionHash: string; getMetadata?: () => Promise; } /** Additional options for the {@link ColonyEventManager} */ export interface ColonyEventManagerOptions { /** Provide a custom {@link IpfsAdapter} */ ipfsAdapter?: IpfsAdapter; } /** * The ColonyEvents class is a wrapper around _ethers_'s event implementations to make it easier to track and fetch Colony related events. * It works by creating specific filters that can keep track of event sources and map filters to their respective events. This allows for * easy parsing of event data, without necessarily knowing the contract that emitted it. * * @remarks * The API is subject to change as we find more applications for this */ export declare class ColonyEventManager { ipfs: IpfsMetadata; provider: providers.JsonRpcProvider; /** * Create a new ColonyEvents instance * * @remarks * As opposed to the {@link ColonyNetwork} class, this constructor _needs_ an _ethers_ JsonRpcProvider (or a subclass of it) as it's * the only provider that supports topic filtering by multiple addresses * * @param provider - An _ethers_ `JsonRpcProvider` * @param options - Optional custom {@link ColonyEventManagerOptions} * @returns A ColonyEvents instance */ constructor(provider: providers.JsonRpcProvider, options?: ColonyEventManagerOptions); private static extractSingleTopic; /** * Create an event source to create filters with * * This method can be used to instantiate contract event sources from virtually any * TypeChain ContractFactory (has to have the `.connect()` method) that can then * be used with the EventManager. Best to use with the contracts from `@colony/events` * as they all are compatible * * @example * Create an event source from the IColonyEventsFactory * ```typescript * import { ColonyEventManager } from '@colony/sdk'; * import { IColonyEvents__factory as ColonyEventsFactory } from '@colony/events'; * * const manager = new ColonyEventManager(provider); * // Event source that can be plugged into a filter creation method * const colonyEventSource = manager.createEventSource(ColonyEventsFactory); * ``` * * @param contractFactory - A TypeChain compatible contract factory * @returns An event source contract (it's just an ethers `Contract`) */ createEventSource(contractFactory: ContractFactory): T; /** * Get events for a single filter * * Gets events for an individual filter and automatically parses the data if possible * * @example * Retrieve and parse all `DomainAdded` events for a specific {@link Colony} contract * ```typescript * const domainAdded = colonyEvents.createFilter( * colonyEventSource, * 'DomainAdded(address,uint256)', * colonyAddress, * ); * // Immediately executing async function * (async function() { * const events = await colonyEvents.getEvents(domainAdded); * })(); * ``` * * @param filter - A {@link ColonyFilter}, {@link ColonyMultiFilter}s will not work * @returns An array of {@link ColonyEvent}s */ getEvents(filter: ColonyFilter): Promise>>; /** * Get events for multiple filters across multiple addresses at once * * All the filters are connected by a logical OR, i.e. it will find ALL given events for ALL the given contract addresses * This is handy when you want to listen to a fixed set of events for a lot of different contracts * * @remarks * `fromBlock` and `toBlock` properties of the indivdual filters will be ignored * * @example * Retrieve and parse all `DomainAdded` and `DomainMetadata` events for a specific {@link ColonyNetwork} contract. * Note that we're using {@link createMultiFilter} here. The two `colonyAddress`es could also be different * * ```typescript * const domainAdded = colonyEvents.createMultiFilter( * colonyEventSource, * 'DomainAdded(address,uint256)', * colonyAddress, * ); * const domainMetadata = colonyEvents.createMultiFilter( * colonyEventSource, * 'DomainMetadata(address,uint256,string)', * colonyAddress, * ); * * // Immediately executing async function * (async function() { * const events = await colonyEvents.getMultiEvents([domainAdded, domainMetadata]); * })(); * ``` * * @param filters - An array of {@link ColonyMultiFilter}s. Normal {@link ColonyFilter}s will not work * @param options - You can define `fromBlock` and `toBlock` only once for all the filters given (default for both is `latest`) * @returns An array of {@link ColonyEvent}s */ getMultiEvents(filters: ColonyMultiFilter | ColonyMultiFilter[], options?: { fromBlock?: BlockTag; toBlock?: BlockTag; }): Promise[]>; /** * Create a {@link ColonyFilter} that keeps track of its event source * * To create a {@link ColonyFilter}, we need to not only give it the topics and addresses as required by _ethers_ * [`Filter`s](https://docs.ethers.io/v5/api/providers/types/#providers-Filter), but also the actual source contract of that Filter. * Like this we can keep track of the source contract interface to parse the event data when it's emitted * * @remarks * We can do that as we do not have ambiguous events across our contracts, so we will always be able to find the right contract to parse the event data later on * * @example * Filter for all `DomainAdded` events between block 21830000 and 21840000 (across all deployed {@link ColonyNetwork} contracts) * ```typescript * const domainAdded = colonyEvents.createFilter( * colonyEventSource, * 'DomainAdded(address,uint256)', * null, * { fromBlock: 21830000 , toBlock: 21840000 }, * ); * ``` * * @typeParam T - Needs to be a valid {@link EventSource} (i.e. from `colonyEvents.eventSources`) * @typeParam N - An event signature as defined in the _ethers_ contract's [`filters`](https://docs.ethers.io/v5/api/contract/contract/#Contract--filters) object. * See the [ColonyJS documentation](https://colony.gitbook.io/colony/colonyjs) for a list of all available contracts and events * * @param contract - A valid {@link EventSource} * @param eventName - A valid event signature from the contract's `filters` object * @param address - Address of the contract that can emit this event. Will listen to any contract if not provided * @param params - Parameters to filter by for the event. Has to be indexed in the contract (see _ethers_ [Event Filters](https://docs.ethers.io/v5/api/contract/contract/#Contract--filters)) * @param options - You can define `fromBlock` and `toBlock` only once for all the filters given (default for both is `latest`) * @returns A {@link ColonyFilter} */ createFilter EventFilter; }; }, N extends keyof T['filters']>(eventSource: T, eventName: N, address?: string, params?: Parameters, options?: { fromBlock?: BlockTag; toBlock?: BlockTag; }): ColonyFilter; /** * Create a {@link ColonyMultiFilter} that keeps track of its event source and can work alongside other filters in {@link getMultiEvents} * * The {@link ColonyMultiFilter} works much like the {@link ColonyFilter}, just that we _have_ to specify an address of the contract which emits this event. * Furthermore, no `fromBlock` or `toBlock` requirements can be given (that is done on a global level in {@link getMultiEvents}) * * @remarks * We can do that as we do not have ambiguous events across our contracts, so we will always be able to find the right contract to parse the event data later on. Note that `ColonyMultiFilter` does not allow for params to be passed in. * * @example * Filter for all `DomainAdded` events for a specific {@link Colony} contract * ```typescript * const domainAdded = colonyEvents.createFilter( * colonyEventSource, * 'DomainAdded(address,uint256)', * colonyAddress, * ); * ``` * * @typeParam T - Needs to be a valid {@link EventSource} (i.e. from `colonyEvents.eventSources`) * @typeParam N - An event signature as defined in the _ethers_ contract's [`filters`](https://docs.ethers.io/v5/api/contract/contract/#Contract--filters) object. * See the [ColonyJS documentation](https://colony.gitbook.io/colony/colonyjs) for a list of all available contracts and events * * @param contract - A valid {@link EventSource} * @param eventNames - A list of valid event signatures from the contract's `filters` object * @param address - Address of the contract that can emit this event. Will listen to any contract if not provided * @returns A {@link ColonyMultiFilter} */ createMultiFilter EventFilter; }; }, N extends keyof T['filters']>(contract: T, eventNames: N[], address?: string): ColonyMultiFilter; } export {};