-
Notifications
You must be signed in to change notification settings - Fork 91
Expand file tree
/
Copy pathsubgraph-client.ts
More file actions
124 lines (106 loc) · 3.52 KB
/
subgraph-client.ts
File metadata and controls
124 lines (106 loc) · 3.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import { DataAccessTypes, StorageTypes } from '@requestnetwork/types';
import { GraphQLClient, Variables } from 'graphql-request';
import {
GetBlockQuery,
GetTransactionByDataHashQuery,
GetTransactionsByChannelIdQuery,
GetTransactionsByHashQuery,
GetTransactionsByTopics,
Meta,
Transaction,
TransactionsBody,
} from './queries';
// Max Int value (as supported by grapqhl types)
const MAX_INT_VALUE = 0x7fffffff;
type RequestConfig = (typeof GraphQLClient.prototype)['requestConfig'];
type ClientConfig = Omit<RequestConfig, 'headers'> & { headers?: Record<string, string> };
export class SubgraphClient implements StorageTypes.IIndexer {
private graphql: GraphQLClient;
public readonly endpoint: string;
private readonly DEFAULT_PAGE_SIZE = 100;
private readonly MAX_PAGE_SIZE = 1000;
constructor(endpoint: string, options?: ClientConfig) {
this.endpoint = endpoint;
this.graphql = new GraphQLClient(endpoint, options);
}
public async initialize(): Promise<void> {
await this.getBlockNumber();
}
public async getBlockNumber(): Promise<number> {
const { _meta } = await this.graphql.request<Meta>(GetBlockQuery);
return _meta.block.number;
}
public getTransactionsByStorageLocation(
hash: string,
): Promise<StorageTypes.IGetTransactionsResponse> {
return this.fetchAndFormat(GetTransactionsByHashQuery, { hash });
}
public getTransactionsByChannelId(
channelId: string,
updatedBetween?: DataAccessTypes.ITimestampBoundaries,
): Promise<StorageTypes.IGetTransactionsResponse> {
return this.fetchAndFormat(GetTransactionsByChannelIdQuery, {
channelId,
...this.getTimeVariables(updatedBetween),
});
}
public async getTransactionsByTopics(
topics: string[],
): Promise<StorageTypes.IGetTransactionsResponse> {
const { _meta, channels } = await this.graphql.request<
Meta & { channels: { transactions: Transaction[] }[] }
>(GetTransactionsByTopics, {
topics,
});
const transactionsByChannel = channels
.map(({ transactions }) => transactions)
.flat()
.sort((a, b) => a.blockTimestamp - b.blockTimestamp);
const indexedTransactions = transactionsByChannel.map(this.toIndexedTransaction);
return {
transactions: indexedTransactions,
blockNumber: _meta.block.number,
};
}
public async getTransactionsByDataHash(
dataHash: string,
): Promise<StorageTypes.IGetTransactionsResponse> {
return await this.fetchAndFormat(GetTransactionByDataHashQuery, { dataHash });
}
private async fetchAndFormat(
query: string,
parameters: Variables | undefined,
): Promise<StorageTypes.IGetTransactionsResponse> {
const { _meta, transactions } = await this.graphql.request<TransactionsBody>(query, parameters);
return {
transactions: transactions.map(this.toIndexedTransaction),
blockNumber: _meta.block.number,
};
}
private toIndexedTransaction({
publicKeys,
encryptedKeys,
...transaction
}: Transaction): StorageTypes.IIndexedTransaction {
return {
...transaction,
keys:
publicKeys?.reduce(
(prev, curr, i) => ({
...prev,
[curr]: encryptedKeys?.[i] || '',
}),
{} as Record<string, string>,
) || undefined,
};
}
private getTimeVariables(updatedBetween?: DataAccessTypes.ITimestampBoundaries) {
if (!updatedBetween) {
updatedBetween = {};
}
return {
from: updatedBetween.from || 0,
to: updatedBetween.to || MAX_INT_VALUE,
};
}
}