@dorafactory/maci-sdk 0.0.19 → 0.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,6 +5,12 @@ import {
5
5
  RoundsCountGraphqlResponse,
6
6
  OperatorResponse,
7
7
  OperatorsResponse,
8
+ OperatorDelayOperationsResponse,
9
+ OperatorDelayOperationsGraphqlResponse,
10
+ MissRateResponse,
11
+ MissRateType,
12
+ TransactionsGraphqlResponse,
13
+ RoundsGraphqlResponse,
8
14
  } from '../../types';
9
15
  import { isValidAddress } from '../../utils';
10
16
  import { handleError, ErrorType } from '../errors';
@@ -131,6 +137,79 @@ export class Operator {
131
137
  }
132
138
  }
133
139
 
140
+ async getOperatorDelayOperationsByAddress(
141
+ address: string,
142
+ after: string,
143
+ limit?: number
144
+ ): Promise<OperatorDelayOperationsResponse> {
145
+ try {
146
+ if (!isValidAddress(address)) {
147
+ return {
148
+ code: 400,
149
+ error: {
150
+ message: 'Invalid operator address format',
151
+ type: ERROR.ERROR_OPERATOR_INVALID_ADDRESS,
152
+ },
153
+ };
154
+ }
155
+
156
+ const OPERATORS_QUERY = `query ($limit: Int, $after: Cursor) {
157
+ operatorDelayOperations(first: $limit, after: $after, filter: {operatorAddress: {equalTo: "${address}"}}, orderBy: [TIMESTAMP_DESC]) {
158
+ pageInfo {
159
+ endCursor
160
+ hasNextPage
161
+ }
162
+ totalCount
163
+ edges {
164
+ cursor
165
+ node {
166
+ blockHeight
167
+ delayProcessDmsgCount
168
+ delayDuration
169
+ delayReason
170
+ delayType
171
+ id
172
+ nodeId
173
+ operatorAddress
174
+ timestamp
175
+ roundAddress
176
+ }
177
+ }
178
+ }
179
+ }`;
180
+
181
+ const response =
182
+ await this.http.fetchGraphql<OperatorDelayOperationsGraphqlResponse>(
183
+ OPERATORS_QUERY,
184
+ after,
185
+ limit
186
+ );
187
+
188
+ if (
189
+ !response ||
190
+ !response.data ||
191
+ !response.data.operatorDelayOperations ||
192
+ !response.data.operatorDelayOperations.edges ||
193
+ response.data.operatorDelayOperations.edges.length === 0
194
+ ) {
195
+ return {
196
+ code: 404,
197
+ error: {
198
+ message: `No operatorDelayOperations found for address ${address}`,
199
+ type: ERROR.ERROR_OPERATOR_DELAY_HISTORY_NOT_FOUND,
200
+ },
201
+ };
202
+ }
203
+ const operator: OperatorDelayOperationsResponse = {
204
+ code: 200,
205
+ data: response.data,
206
+ };
207
+ return operator;
208
+ } catch (error) {
209
+ return handleError(error as ErrorType);
210
+ }
211
+ }
212
+
134
213
  async getOperators(
135
214
  after: string,
136
215
  limit?: number
@@ -260,4 +339,263 @@ export class Operator {
260
339
  return handleError(error as ErrorType);
261
340
  }
262
341
  }
342
+
343
+ async queryMissRate(
344
+ address: string,
345
+ durationDay: number
346
+ ): Promise<MissRateResponse> {
347
+ try {
348
+ const now = new Date();
349
+ const startTime = new Date(
350
+ now.getTime() - durationDay * 24 * 60 * 60 * 1000
351
+ );
352
+ const startTimestamp = Math.floor(startTime.getTime() / 1000);
353
+ const endNanosTimestamp = Math.floor(startTime.getTime() * 1000000);
354
+ const txTimestamp = Math.floor(startTime.getTime());
355
+
356
+ const QUERY = `query ($limit: Int, $after: Cursor) {
357
+ operatorDelayOperations(
358
+ first: $limit,
359
+ after: $after,
360
+ filter: {
361
+ operatorAddress: {equalTo: "${address}"},
362
+ timestamp: { greaterThanOrEqualTo: "${startTimestamp}" }
363
+ },
364
+ orderBy: [TIMESTAMP_DESC]
365
+ ) {
366
+ edges {
367
+ node {
368
+ blockHeight
369
+ delayProcessDmsgCount
370
+ delayDuration
371
+ delayReason
372
+ delayType
373
+ id
374
+ nodeId
375
+ operatorAddress
376
+ timestamp
377
+ roundAddress
378
+ }
379
+ }
380
+ }
381
+ }`;
382
+
383
+ const ROUNDS_QUERY = `query ($limit: Int, $after: Cursor) {
384
+ rounds(first: $limit, after: $after,
385
+ filter: {
386
+ operator: {equalTo: "${address}"},
387
+ votingEnd: { greaterThanOrEqualTo: "${endNanosTimestamp}" }
388
+ },
389
+ orderBy: [TIMESTAMP_DESC]
390
+ ){
391
+ pageInfo {
392
+ endCursor
393
+ hasNextPage
394
+ }
395
+ totalCount
396
+ edges {
397
+ node {
398
+ id
399
+ blockHeight
400
+ txHash
401
+ caller
402
+ admin
403
+ operator
404
+ contractAddress
405
+ circuitName
406
+ timestamp
407
+ votingStart
408
+ votingEnd
409
+ status
410
+ period
411
+ actionType
412
+ roundTitle
413
+ roundDescription
414
+ roundLink
415
+ coordinatorPubkeyX
416
+ coordinatorPubkeyY
417
+ voteOptionMap
418
+ results
419
+ allResult
420
+ gasStationEnable
421
+ totalGrant
422
+ baseGrant
423
+ totalBond
424
+ circuitType
425
+ circuitPower
426
+ certificationSystem
427
+ codeId
428
+ maciType
429
+ voiceCreditAmount
430
+ preDeactivateRoot
431
+ }
432
+ cursor
433
+ }
434
+ }
435
+ }
436
+ `;
437
+
438
+ const roundsResponse =
439
+ await this.http.fetchGraphql<RoundsGraphqlResponse>(
440
+ ROUNDS_QUERY,
441
+ '',
442
+ 9999
443
+ );
444
+ const roundContractAddresses =
445
+ roundsResponse?.data?.rounds?.edges?.map(
446
+ (edge) => edge.node.contractAddress
447
+ ) || [];
448
+
449
+ const TRANSACTIONS_QUERY = `query transactions($limit: Int, $after: Cursor) {
450
+ transactions(first: $limit, after: $after,
451
+ filter: {
452
+ timestamp: { greaterThanOrEqualTo: "${txTimestamp}" },
453
+ type: { equalTo: "op:procDeactivate" },
454
+ contractAddress: { in: ${JSON.stringify(roundContractAddresses)} }
455
+ },
456
+ orderBy: [TIMESTAMP_DESC]
457
+ ){
458
+ pageInfo {
459
+ endCursor
460
+ hasNextPage
461
+ }
462
+ totalCount
463
+ edges {
464
+ cursor
465
+ node {
466
+ id
467
+ blockHeight
468
+ txHash
469
+ timestamp
470
+ type
471
+ status
472
+ circuitName
473
+ fee
474
+ gasUsed
475
+ gasWanted
476
+ caller
477
+ contractAddress
478
+ }
479
+ }
480
+ }
481
+ }`;
482
+
483
+ const [delayResponse, transactionsResponse] = await Promise.all([
484
+ this.http.fetchGraphql<OperatorDelayOperationsGraphqlResponse>(
485
+ QUERY,
486
+ '',
487
+ 9999
488
+ ),
489
+ this.http.fetchGraphql<TransactionsGraphqlResponse>(
490
+ TRANSACTIONS_QUERY,
491
+ '',
492
+ 9999
493
+ ),
494
+ ]);
495
+
496
+ const dailyStats = new Map<string, MissRateType>();
497
+
498
+ const endDate = new Date();
499
+ for (let i = 0; i < durationDay; i++) {
500
+ const date = new Date(endDate.getTime() - i * 24 * 60 * 60 * 1000)
501
+ .toISOString()
502
+ .split('T')[0];
503
+ dailyStats.set(date, {
504
+ delayCount: 0,
505
+ deactivateDelay: {
506
+ count: 0,
507
+ dmsgCount: 0,
508
+ },
509
+ tallyDelay: {
510
+ count: 0,
511
+ },
512
+ totalDelayDuration: 0,
513
+ avgDelayDuration: 0,
514
+ tallyCount: 0,
515
+ deactivateCount: 0,
516
+ missRate: 0,
517
+ });
518
+ }
519
+
520
+ delayResponse.data.operatorDelayOperations.edges.forEach(({ node }) => {
521
+ const date = new Date(parseInt(node.timestamp) * 1000)
522
+ .toISOString()
523
+ .split('T')[0];
524
+
525
+ if (dailyStats.has(date)) {
526
+ const stats = dailyStats.get(date)!;
527
+ stats.delayCount++;
528
+ stats.totalDelayDuration += parseInt(node.delayDuration);
529
+ if (node.delayType === 'deactivate_delay') {
530
+ stats.deactivateDelay.count++;
531
+ stats.deactivateDelay.dmsgCount += node.delayProcessDmsgCount;
532
+ } else if (node.delayType === 'tally_delay') {
533
+ stats.tallyDelay.count++;
534
+ }
535
+ }
536
+ });
537
+
538
+ if (roundsResponse?.data?.rounds?.edges) {
539
+ roundsResponse.data.rounds.edges.forEach(({ node }) => {
540
+ const date = new Date(parseInt(node.votingEnd) / 1000000)
541
+ .toISOString()
542
+ .split('T')[0];
543
+ if (dailyStats.has(date)) {
544
+ const stats = dailyStats.get(date)!;
545
+ stats.tallyCount++;
546
+ }
547
+ });
548
+ }
549
+
550
+ if (transactionsResponse?.data?.transactions?.edges) {
551
+ transactionsResponse.data.transactions.edges.forEach(({ node }) => {
552
+ const date = new Date(parseInt(node.timestamp))
553
+ .toISOString()
554
+ .split('T')[0];
555
+ if (dailyStats.has(date)) {
556
+ const stats = dailyStats.get(date)!;
557
+ stats.deactivateCount++;
558
+ }
559
+ });
560
+ }
561
+
562
+ return {
563
+ code: 200,
564
+ data: {
565
+ missRate: Array.from(dailyStats.entries())
566
+ .map(([date, stats]) => ({
567
+ date,
568
+ delayCount: stats.delayCount,
569
+ deactivateDelay: stats.deactivateDelay,
570
+ tallyDelay: stats.tallyDelay,
571
+ totalDelayDuration: stats.totalDelayDuration,
572
+ avgDelayDuration:
573
+ stats.delayCount > 0
574
+ ? stats.totalDelayDuration / stats.delayCount
575
+ : 0,
576
+ tallyCount: stats.tallyCount,
577
+ deactivateCount: stats.deactivateCount,
578
+ missRate:
579
+ stats.deactivateCount + stats.tallyCount > 0
580
+ ? parseFloat(
581
+ (
582
+ (stats.deactivateDelay.count + stats.tallyDelay.count) /
583
+ (stats.deactivateCount + stats.tallyCount)
584
+ ).toFixed(2)
585
+ )
586
+ : 0,
587
+ }))
588
+ .sort((a, b) => b.date.localeCompare(a.date)),
589
+ },
590
+ };
591
+ } catch (error) {
592
+ return {
593
+ code: 404,
594
+ error: {
595
+ message: 'Query miss rate failed',
596
+ type: ERROR.ERROR_QUERY_MISS_RATE_FAILED,
597
+ },
598
+ };
599
+ }
600
+ }
263
601
  }
@@ -114,6 +114,19 @@ export type ProofType = {
114
114
  }[];
115
115
  };
116
116
 
117
+ export type OperatorDelayType = {
118
+ blockHeight: string;
119
+ delayProcessDmsgCount: number;
120
+ delayDuration: string;
121
+ delayReason: string;
122
+ delayType: string;
123
+ id: string;
124
+ nodeId: string;
125
+ operatorAddress: string;
126
+ timestamp: string;
127
+ roundAddress: string;
128
+ };
129
+
117
130
  export type OperatorType = {
118
131
  id: string;
119
132
  validatorAddress: string;
@@ -192,6 +205,36 @@ export type OperatorResponse =
192
205
  }>
193
206
  | ErrorResponse;
194
207
 
208
+ export type MissRateResponse =
209
+ | SuccessResponse<{
210
+ missRate: (MissRateType & {
211
+ date: string;
212
+ })[];
213
+ }>
214
+ | ErrorResponse;
215
+
216
+ // export type ClaimableResponse =
217
+ // | SuccessResponse<{
218
+ // claimable: ClaimableType;
219
+ // }>
220
+ // | ErrorResponse;
221
+
222
+ export type OperatorDelayOperationsResponse =
223
+ | SuccessResponse<{
224
+ operatorDelayOperations: {
225
+ pageInfo: {
226
+ endCursor: string;
227
+ hasNextPage: boolean;
228
+ };
229
+ edges: {
230
+ cursor: string;
231
+ node: OperatorDelayType;
232
+ }[];
233
+ totalCount: number;
234
+ };
235
+ }>
236
+ | ErrorResponse;
237
+
195
238
  export type OperatorsResponse =
196
239
  | SuccessResponse<{
197
240
  operators: {
@@ -235,6 +278,33 @@ export type RoundsCountGraphqlResponse = {
235
278
  };
236
279
  };
237
280
 
281
+ export type VoteCountGraphqlResponse = {
282
+ data: {
283
+ signupsCount: {
284
+ totalCount: number;
285
+ };
286
+ messagesCount: {
287
+ totalCount: number;
288
+ };
289
+ };
290
+ };
291
+
292
+ export type OperatorDelayOperationsGraphqlResponse = {
293
+ data: {
294
+ operatorDelayOperations: {
295
+ pageInfo: {
296
+ endCursor: string;
297
+ hasNextPage: boolean;
298
+ };
299
+ edges: {
300
+ cursor: string;
301
+ node: OperatorDelayType;
302
+ }[];
303
+ totalCount: number;
304
+ };
305
+ };
306
+ };
307
+
238
308
  export type TransactionGraphqlResponse = {
239
309
  data: {
240
310
  transaction: TransactionType;
@@ -348,3 +418,19 @@ export type SignUpEventsGraphqlResponse = {
348
418
  };
349
419
  };
350
420
  };
421
+
422
+ export type MissRateType = {
423
+ delayCount: number;
424
+ deactivateDelay: {
425
+ count: number;
426
+ dmsgCount: number;
427
+ };
428
+ tallyDelay: {
429
+ count: number;
430
+ };
431
+ totalDelayDuration: number;
432
+ avgDelayDuration: number;
433
+ tallyCount: number;
434
+ deactivateCount: number;
435
+ missRate: number;
436
+ };