UNPKG

9.68 kBPlain TextView Raw
1import { providers } from "ethers";
2
3import {
4 AppChallenge,
5 ChallengeEvent,
6 ChallengeEventData,
7 ChallengeUpdatedEventPayload,
8 SignedCancelChallengeRequest,
9 StateProgressedEventPayload,
10 ChallengeEvents,
11 ContractAddresses,
12} from "./contracts";
13import { StateChannelJSON } from "./state";
14import { Address, Bytes32 } from "./basic";
15import { AppInstanceJson } from "./app";
16import {
17 ConditionalTransactionCommitmentJSON,
18 MinimalTransaction,
19 SetStateCommitmentJSON,
20} from "./commitments";
21import { IChannelSigner } from "./crypto";
22import { ILoggerService, ILogger } from "./logger";
23import { Ctx } from "evt";
24
25////////////////////////////////////////
26// Watcher external parameters
27
28export type WatcherInitOptions = {
29 signer: IChannelSigner | string; // wallet or pk
30 provider: providers.JsonRpcProvider | string;
31 context: ContractAddresses;
32 store: IWatcherStoreService;
33 logger?: ILoggerService | ILogger;
34 logLevel?: number;
35};
36
37////////////////////////////////////////
38// Watcher Events
39
40type BaseChallengeTransactionCompletedEvent = {
41 transaction: providers.TransactionReceipt;
42 appInstanceId: Bytes32;
43 multisigAddress: Address;
44};
45type BaseChallengeTransactionFailedEvent = {
46 appInstanceId: Bytes32;
47 error: string;
48 multisigAddress: Address;
49 challenge: StoredAppChallenge | undefined;
50 params: any; // ProgressStateParams | SetStateParams | CancelChallengeParams
51};
52
53////////////////////////////////////////
54export const ChallengeProgressedEvent = "ChallengeProgressedEvent";
55export type ChallengeProgressedEventData = BaseChallengeTransactionCompletedEvent;
56
57////////////////////////////////////////
58export const ChallengeProgressionFailedEvent = "ChallengeProgressionFailedEvent";
59export type ChallengeProgressionFailedEventData = BaseChallengeTransactionFailedEvent;
60
61////////////////////////////////////////
62export const ChallengeCompletedEvent = "ChallengeCompletedEvent";
63export type ChallengeCompletedEventData = BaseChallengeTransactionCompletedEvent;
64
65////////////////////////////////////////
66export const ChallengeCompletionFailedEvent = "ChallengeCompletionFailedEvent";
67export type ChallengeCompletionFailedEventData = BaseChallengeTransactionFailedEvent;
68
69////////////////////////////////////////
70export const ChallengeOutcomeSetEvent = "ChallengeOutcomeSetEvent";
71export type ChallengeOutcomeSetEventData = BaseChallengeTransactionCompletedEvent;
72
73////////////////////////////////////////
74export const ChallengeOutcomeFailedEvent = "ChallengeOutcomeFailedEvent";
75export type ChallengeOutcomeFailedEventData = BaseChallengeTransactionFailedEvent;
76
77////////////////////////////////////////
78export const ChallengeCancelledEvent = "ChallengeCancelledEvent";
79export type ChallengeCancelledEventData = BaseChallengeTransactionCompletedEvent;
80
81////////////////////////////////////////
82export const ChallengeCancellationFailedEvent = "ChallengeCancellationFailedEvent";
83export type ChallengeCancellationFailedEventData = BaseChallengeTransactionFailedEvent;
84
85////////////////////////////////////////
86/// From contracts
87export const ChallengeUpdatedEvent = "ChallengeUpdatedEvent";
88export type ChallengeUpdatedEventData = ChallengeEventData[typeof ChallengeEvents.ChallengeUpdated];
89
90export const StateProgressedEvent = "StateProgressedEvent";
91export type StateProgressedEventData = ChallengeEventData[typeof ChallengeEvents.StateProgressed];
92
93////////////////////////////////////////
94export const WatcherEvents = {
95 [ChallengeUpdatedEvent]: ChallengeUpdatedEvent,
96 [StateProgressedEvent]: StateProgressedEvent,
97 [ChallengeProgressedEvent]: ChallengeProgressedEvent,
98 [ChallengeProgressionFailedEvent]: ChallengeProgressionFailedEvent,
99 [ChallengeOutcomeSetEvent]: ChallengeOutcomeSetEvent,
100 [ChallengeOutcomeFailedEvent]: ChallengeOutcomeFailedEvent,
101 [ChallengeCompletedEvent]: ChallengeCompletedEvent,
102 [ChallengeCompletionFailedEvent]: ChallengeCompletionFailedEvent,
103 [ChallengeCancelledEvent]: ChallengeCancelledEvent,
104 [ChallengeCancellationFailedEvent]: ChallengeCancellationFailedEvent,
105} as const;
106export type WatcherEvent = keyof typeof WatcherEvents;
107
108interface WatcherEventDataMap {
109 [ChallengeUpdatedEvent]: ChallengeUpdatedEventData;
110 [StateProgressedEvent]: StateProgressedEventData;
111 [ChallengeProgressedEvent]: ChallengeProgressedEventData;
112 [ChallengeProgressionFailedEvent]: ChallengeProgressionFailedEventData;
113 [ChallengeOutcomeFailedEvent]: ChallengeOutcomeFailedEventData;
114 [ChallengeOutcomeSetEvent]: ChallengeOutcomeSetEventData;
115 [ChallengeCompletedEvent]: ChallengeCompletedEventData;
116 [ChallengeCompletionFailedEvent]: ChallengeCompletionFailedEventData;
117 [ChallengeCancelledEvent]: ChallengeCancelledEventData;
118 [ChallengeCancellationFailedEvent]: ChallengeCancellationFailedEventData;
119}
120export type WatcherEventData = {
121 [P in keyof WatcherEventDataMap]: WatcherEventDataMap[P];
122};
123
124////////////////////////////////////////
125// Listener Events
126
127////////////////////////////////////////
128// Watcher interface
129
130export type ChallengeInitiatedResponse = {
131 freeBalanceChallenge: providers.TransactionReceipt;
132 appChallenge: providers.TransactionReceipt;
133};
134
135export interface IWatcher {
136 //////// Listener methods
137 emit<T extends WatcherEvent>(event: T, data: WatcherEventData[T]): void;
138 on<T extends WatcherEvent>(
139 event: T,
140 callback: (data: WatcherEventData[T]) => Promise<void>,
141 filter?: (payload: WatcherEventData[T]) => boolean,
142 ): void;
143 once<T extends WatcherEvent>(
144 event: T,
145 callback: (data: WatcherEventData[T]) => Promise<void>,
146 filter?: (payload: WatcherEventData[T]) => boolean,
147 ): void;
148 waitFor<T extends WatcherEvent>(
149 event: T,
150 timeout: number,
151 filter?: (payload: WatcherEventData[T]) => boolean,
152 ): Promise<WatcherEventData[T]>;
153 off(): void;
154
155 //////// Public methods
156 enable(): Promise<void>;
157 disable(): Promise<void>;
158 initiate(appIdentityHash: string): Promise<ChallengeInitiatedResponse>;
159 cancel(
160 appIdentityHash: string,
161 req: SignedCancelChallengeRequest,
162 ): Promise<providers.TransactionReceipt>;
163}
164
165////////////////////////////////////////
166// Listener interface
167
168export interface IChainListener {
169 //////// Evt methods
170 attach<T extends ChallengeEvent>(
171 event: T,
172 callback: (data: ChallengeEventData[T]) => Promise<void>,
173 providedFilter?: (data: ChallengeEventData[T]) => boolean,
174 ctx?: Ctx<ChallengeEventData[T]>,
175 ): void;
176
177 attachOnce<T extends ChallengeEvent>(
178 event: T,
179 callback: (data: ChallengeEventData[T]) => Promise<void>,
180 providedFilter?: (data: ChallengeEventData[T]) => boolean,
181 ctx?: Ctx<ChallengeEventData[T]>,
182 ): void;
183
184 waitFor<T extends ChallengeEvent>(
185 event: T,
186 timeout: number,
187 providedFilter?: (data: ChallengeEventData[T]) => boolean,
188 ctx?: Ctx<ChallengeEventData[T]>,
189 ): Promise<ChallengeEventData[T]>;
190
191 createContext<T extends ChallengeEvent>(): Ctx<ChallengeEventData[T]>;
192 detach<T extends ChallengeEvent>(ctx?: Ctx<ChallengeEventData[T]>): void;
193
194 //////// Public methods
195 enable(): Promise<void>;
196 disable(): Promise<void>;
197 parseLogsFrom(startingBlock: number): Promise<void>;
198}
199
200////////////////////////////////////////
201// Storage
202// The status of a challenge in the ChallengeRegistry
203export enum StoredAppChallengeStatus {
204 NO_CHALLENGE = 0,
205 IN_DISPUTE = 1,
206 IN_ONCHAIN_PROGRESSION = 2,
207 EXPLICITLY_FINALIZED = 3,
208 OUTCOME_SET = 4,
209 CONDITIONAL_SENT = 5,
210 PENDING_TRANSITION = 6,
211}
212export type StoredAppChallenge = Omit<AppChallenge, "status"> & {
213 identityHash: Bytes32;
214 status: StoredAppChallengeStatus;
215};
216
217export interface IWatcherStoreService {
218 // Disputes
219 getAppChallenge(appIdentityHash: Bytes32): Promise<StoredAppChallenge | undefined>;
220 saveAppChallenge(data: ChallengeUpdatedEventPayload | StoredAppChallenge): Promise<void>;
221 getActiveChallenges(): Promise<StoredAppChallenge[]>;
222
223 // Events
224 getLatestProcessedBlock(): Promise<number>;
225 updateLatestProcessedBlock(blockNumber: number): Promise<void>;
226
227 getStateProgressedEvents(appIdentityHash: Bytes32): Promise<StateProgressedEventPayload[]>;
228 createStateProgressedEvent(event: StateProgressedEventPayload): Promise<void>;
229
230 getChallengeUpdatedEvents(appIdentityHash: Bytes32): Promise<ChallengeUpdatedEventPayload[]>;
231 createChallengeUpdatedEvent(event: ChallengeUpdatedEventPayload): Promise<void>;
232
233 addOnchainAction(appIdentityHash: Bytes32, provider: providers.JsonRpcProvider): Promise<void>;
234
235 ////////////////////////////////////////
236 //// Channel data
237
238 // Schema version
239 getSchemaVersion(): Promise<number>;
240
241 // State channels
242 getAllChannels(): Promise<StateChannelJSON[]>;
243 getStateChannel(multisigAddress: Address): Promise<StateChannelJSON | undefined>;
244 getStateChannelByOwnersAndChainId(
245 owners: Address[],
246 chainId: number,
247 ): Promise<StateChannelJSON | undefined>;
248 getStateChannelByAppIdentityHash(appIdentityHash: Bytes32): Promise<StateChannelJSON | undefined>;
249
250 // App instances
251 getAppInstance(appIdentityHash: Bytes32): Promise<AppInstanceJson | undefined>;
252
253 // App proposals
254 getAppProposal(appIdentityHash: Bytes32): Promise<AppInstanceJson | undefined>;
255
256 // Free balance
257 getFreeBalance(multisigAddress: Address): Promise<AppInstanceJson | undefined>;
258
259 // Setup commitment
260 getSetupCommitment(multisigAddress: Address): Promise<MinimalTransaction | undefined>;
261
262 // SetState commitment
263 getSetStateCommitments(appIdentityHash: Bytes32): Promise<SetStateCommitmentJSON[]>;
264
265 // Conditional tx commitment
266 getConditionalTransactionCommitment(
267 appIdentityHash: Bytes32,
268 ): Promise<ConditionalTransactionCommitmentJSON | undefined>;
269}