import { providers } from "ethers"; import { AppChallenge, ChallengeEvent, ChallengeEventData, ChallengeUpdatedEventPayload, SignedCancelChallengeRequest, StateProgressedEventPayload, ChallengeEvents, ContractAddresses, } from "./contracts"; import { StateChannelJSON } from "./state"; import { Address, Bytes32 } from "./basic"; import { AppInstanceJson } from "./app"; import { ConditionalTransactionCommitmentJSON, MinimalTransaction, SetStateCommitmentJSON, } from "./commitments"; import { IChannelSigner } from "./crypto"; import { ILoggerService, ILogger } from "./logger"; import { Ctx } from "evt"; //////////////////////////////////////// // Watcher external parameters export type WatcherInitOptions = { signer: IChannelSigner | string; // wallet or pk provider: providers.JsonRpcProvider | string; context: ContractAddresses; store: IWatcherStoreService; logger?: ILoggerService | ILogger; logLevel?: number; }; //////////////////////////////////////// // Watcher Events type BaseChallengeTransactionCompletedEvent = { transaction: providers.TransactionReceipt; appInstanceId: Bytes32; multisigAddress: Address; }; type BaseChallengeTransactionFailedEvent = { appInstanceId: Bytes32; error: string; multisigAddress: Address; challenge: StoredAppChallenge | undefined; params: any; // ProgressStateParams | SetStateParams | CancelChallengeParams }; //////////////////////////////////////// export const ChallengeProgressedEvent = "ChallengeProgressedEvent"; export type ChallengeProgressedEventData = BaseChallengeTransactionCompletedEvent; //////////////////////////////////////// export const ChallengeProgressionFailedEvent = "ChallengeProgressionFailedEvent"; export type ChallengeProgressionFailedEventData = BaseChallengeTransactionFailedEvent; //////////////////////////////////////// export const ChallengeCompletedEvent = "ChallengeCompletedEvent"; export type ChallengeCompletedEventData = BaseChallengeTransactionCompletedEvent; //////////////////////////////////////// export const ChallengeCompletionFailedEvent = "ChallengeCompletionFailedEvent"; export type ChallengeCompletionFailedEventData = BaseChallengeTransactionFailedEvent; //////////////////////////////////////// export const ChallengeOutcomeSetEvent = "ChallengeOutcomeSetEvent"; export type ChallengeOutcomeSetEventData = BaseChallengeTransactionCompletedEvent; //////////////////////////////////////// export const ChallengeOutcomeFailedEvent = "ChallengeOutcomeFailedEvent"; export type ChallengeOutcomeFailedEventData = BaseChallengeTransactionFailedEvent; //////////////////////////////////////// export const ChallengeCancelledEvent = "ChallengeCancelledEvent"; export type ChallengeCancelledEventData = BaseChallengeTransactionCompletedEvent; //////////////////////////////////////// export const ChallengeCancellationFailedEvent = "ChallengeCancellationFailedEvent"; export type ChallengeCancellationFailedEventData = BaseChallengeTransactionFailedEvent; //////////////////////////////////////// /// From contracts export const ChallengeUpdatedEvent = "ChallengeUpdatedEvent"; export type ChallengeUpdatedEventData = ChallengeEventData[typeof ChallengeEvents.ChallengeUpdated]; export const StateProgressedEvent = "StateProgressedEvent"; export type StateProgressedEventData = ChallengeEventData[typeof ChallengeEvents.StateProgressed]; //////////////////////////////////////// export const WatcherEvents = { [ChallengeUpdatedEvent]: ChallengeUpdatedEvent, [StateProgressedEvent]: StateProgressedEvent, [ChallengeProgressedEvent]: ChallengeProgressedEvent, [ChallengeProgressionFailedEvent]: ChallengeProgressionFailedEvent, [ChallengeOutcomeSetEvent]: ChallengeOutcomeSetEvent, [ChallengeOutcomeFailedEvent]: ChallengeOutcomeFailedEvent, [ChallengeCompletedEvent]: ChallengeCompletedEvent, [ChallengeCompletionFailedEvent]: ChallengeCompletionFailedEvent, [ChallengeCancelledEvent]: ChallengeCancelledEvent, [ChallengeCancellationFailedEvent]: ChallengeCancellationFailedEvent, } as const; export type WatcherEvent = keyof typeof WatcherEvents; interface WatcherEventDataMap { [ChallengeUpdatedEvent]: ChallengeUpdatedEventData; [StateProgressedEvent]: StateProgressedEventData; [ChallengeProgressedEvent]: ChallengeProgressedEventData; [ChallengeProgressionFailedEvent]: ChallengeProgressionFailedEventData; [ChallengeOutcomeFailedEvent]: ChallengeOutcomeFailedEventData; [ChallengeOutcomeSetEvent]: ChallengeOutcomeSetEventData; [ChallengeCompletedEvent]: ChallengeCompletedEventData; [ChallengeCompletionFailedEvent]: ChallengeCompletionFailedEventData; [ChallengeCancelledEvent]: ChallengeCancelledEventData; [ChallengeCancellationFailedEvent]: ChallengeCancellationFailedEventData; } export type WatcherEventData = { [P in keyof WatcherEventDataMap]: WatcherEventDataMap[P]; }; //////////////////////////////////////// // Listener Events //////////////////////////////////////// // Watcher interface export type ChallengeInitiatedResponse = { freeBalanceChallenge: providers.TransactionReceipt; appChallenge: providers.TransactionReceipt; }; export interface IWatcher { //////// Listener methods emit(event: T, data: WatcherEventData[T]): void; on( event: T, callback: (data: WatcherEventData[T]) => Promise, filter?: (payload: WatcherEventData[T]) => boolean, ): void; once( event: T, callback: (data: WatcherEventData[T]) => Promise, filter?: (payload: WatcherEventData[T]) => boolean, ): void; waitFor( event: T, timeout: number, filter?: (payload: WatcherEventData[T]) => boolean, ): Promise; off(): void; //////// Public methods enable(): Promise; disable(): Promise; initiate(appIdentityHash: string): Promise; cancel( appIdentityHash: string, req: SignedCancelChallengeRequest, ): Promise; } //////////////////////////////////////// // Listener interface export interface IChainListener { //////// Evt methods attach( event: T, callback: (data: ChallengeEventData[T]) => Promise, providedFilter?: (data: ChallengeEventData[T]) => boolean, ctx?: Ctx, ): void; attachOnce( event: T, callback: (data: ChallengeEventData[T]) => Promise, providedFilter?: (data: ChallengeEventData[T]) => boolean, ctx?: Ctx, ): void; waitFor( event: T, timeout: number, providedFilter?: (data: ChallengeEventData[T]) => boolean, ctx?: Ctx, ): Promise; createContext(): Ctx; detach(ctx?: Ctx): void; //////// Public methods enable(): Promise; disable(): Promise; parseLogsFrom(startingBlock: number): Promise; } //////////////////////////////////////// // Storage // The status of a challenge in the ChallengeRegistry export enum StoredAppChallengeStatus { NO_CHALLENGE = 0, IN_DISPUTE = 1, IN_ONCHAIN_PROGRESSION = 2, EXPLICITLY_FINALIZED = 3, OUTCOME_SET = 4, CONDITIONAL_SENT = 5, PENDING_TRANSITION = 6, } export type StoredAppChallenge = Omit & { identityHash: Bytes32; status: StoredAppChallengeStatus; }; export interface IWatcherStoreService { // Disputes getAppChallenge(appIdentityHash: Bytes32): Promise; saveAppChallenge(data: ChallengeUpdatedEventPayload | StoredAppChallenge): Promise; getActiveChallenges(): Promise; // Events getLatestProcessedBlock(): Promise; updateLatestProcessedBlock(blockNumber: number): Promise; getStateProgressedEvents(appIdentityHash: Bytes32): Promise; createStateProgressedEvent(event: StateProgressedEventPayload): Promise; getChallengeUpdatedEvents(appIdentityHash: Bytes32): Promise; createChallengeUpdatedEvent(event: ChallengeUpdatedEventPayload): Promise; addOnchainAction(appIdentityHash: Bytes32, provider: providers.JsonRpcProvider): Promise; //////////////////////////////////////// //// Channel data // Schema version getSchemaVersion(): Promise; // State channels getAllChannels(): Promise; getStateChannel(multisigAddress: Address): Promise; getStateChannelByOwnersAndChainId( owners: Address[], chainId: number, ): Promise; getStateChannelByAppIdentityHash(appIdentityHash: Bytes32): Promise; // App instances getAppInstance(appIdentityHash: Bytes32): Promise; // App proposals getAppProposal(appIdentityHash: Bytes32): Promise; // Free balance getFreeBalance(multisigAddress: Address): Promise; // Setup commitment getSetupCommitment(multisigAddress: Address): Promise; // SetState commitment getSetStateCommitments(appIdentityHash: Bytes32): Promise; // Conditional tx commitment getConditionalTransactionCommitment( appIdentityHash: Bytes32, ): Promise; }