Skip to content

Commit 937e6b5

Browse files
committed
'bump'
1 parent 028f5f6 commit 937e6b5

File tree

6 files changed

+94
-36
lines changed

6 files changed

+94
-36
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "dequanto",
3-
"version": "0.1.53",
3+
"version": "0.1.54",
44
"author": {
55
"name": "Alex Kit",
66
"email": "alex.kit@atmajs.com"

src/contracts/ContractReader.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,11 @@ export class ContractReader implements IContractReader {
168168
params?: { [key: string]: any } | any[]
169169

170170
}): Promise<RpcTypes.Filter> {
171+
172+
if (Array.isArray(abi) && abi.length === 1) {
173+
return this.getLogsFilter(abi[0], options);
174+
}
175+
171176
let filters: Partial<RpcTypes.Filter> = {
172177
address: options.address,
173178
};
@@ -227,9 +232,15 @@ export class ContractReader implements IContractReader {
227232
abi.map($abiUtils.getTopicSignature)
228233
];
229234
if (options.params != null) {
230-
let paramsArr = $require.Array(options.params, `Multiple Logs are being requested. The params should be an array. `);
231235
let abiInputsArr = abi.map(x => x.inputs.filter(i => i.indexed));
236+
237+
let paramsArr = Array.isArray(options.params) === false
238+
? [options.params]
239+
: options.params;
240+
232241
let inputsMax = alot(abiInputsArr).max(x => x.length);
242+
$require.gt(inputsMax, 0, `The ABI ${abi[0].name} has no indexed arguments.`);
243+
233244
for (let i = 0; i < inputsMax; i++) {
234245
let options = [];
235246
for (let j = 0; j < abiInputsArr.length; j++) {

src/indexer/EventsIndexer.ts

Lines changed: 64 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { ITxLogItem } from '@dequanto/txs/receipt/ITxLogItem';
77
import { $date } from '@dequanto/utils/$date';
88
import { $require } from '@dequanto/utils/$require';
99
import { TAddress } from '@dequanto/models/TAddress';
10-
import { IEventsIndexerMetaStore, IEventsIndexerStore } from './storage/interfaces';
10+
import { IEventsIndexerMetaStore, IEventsIndexerStore, TEventsIndexerItem } from './storage/interfaces';
1111
import { FsEventsIndexerStore } from './storage/FsEventsIndexerStore';
1212
import { FsEventsMetaStore } from './storage/FsEventsMetaStore';
1313
import { class_Dfr } from 'atma-utils';
@@ -17,12 +17,12 @@ import { TEth } from '@dequanto/models/TEth';
1717
import { l } from '@dequanto/utils/$logger';
1818

1919

20-
export class EventsIndexer <T extends ContractBase> {
20+
export class EventsIndexer <TContract extends ContractBase> {
2121

2222
public store: IEventsIndexerStore
2323
public storeMeta: IEventsIndexerMetaStore
2424

25-
constructor(public contract: T, public options: {
25+
constructor(public contract: TContract, public options: {
2626
// Load events from the contract that was deployed to multiple addresses
2727
addresses?: TAddress[]
2828
name?: string
@@ -71,37 +71,40 @@ export class EventsIndexer <T extends ContractBase> {
7171
$require.True(this.store instanceof FsEventsIndexerStore);
7272
$require.True(this.storeMeta instanceof FsEventsMetaStore);
7373

74-
await (this.store as FsEventsIndexerStore<T>).ensureMigrated();
75-
await (this.storeMeta as FsEventsMetaStore<T>).ensureMigrated();
74+
await (this.store as FsEventsIndexerStore<TContract>).ensureMigrated();
75+
await (this.storeMeta as FsEventsMetaStore<TContract>).ensureMigrated();
7676
}
7777

7878
async getPastLogs <
79-
TLogName extends GetEventLogNames<T>,
79+
TLogName extends GetEventLogNames<TContract>,
8080
> (
8181
event: TLogName | TLogName[] | '*',
82-
// Fetch all logs and filter later if needed
83-
//- params?: T[TMethodName] extends (options: { params?: infer TParams }) => any ? TParams : never,
8482
filter?: {
8583
fromBlock?: number
8684
toBlock?: number
85+
params?: TLogName extends keyof TContract
86+
? (TContract[TLogName] extends (options: { params?: infer TParams }) => any ? TParams : never)
87+
: never,
8788
}
8889
): Promise<{
89-
logs: ITxLogItem<GetTypes<T>['Events'][TLogName]['outputParams']>[],
90+
logs: ITxLogItem<GetTypes<TContract>['Events'][TLogName]['outputParams']>[],
9091
}> {
9192
let contract = this.contract;
9293
let client = contract.client;
9394
let toBlock = filter?.toBlock ?? await client.getBlockNumber();
9495
let events = Array.isArray(event) ? event as string[] : [ event as string ];
95-
let ranges = await this.getRanges(events, this.options.initialBlockNumber, toBlock);
96-
let logs = await this.getPastLogsRanges(ranges, events, toBlock, filter?.fromBlock);
97-
96+
let filterKey = this.getFilterKey(filter?.params);
97+
let ranges = await this.getRanges(events, this.options.initialBlockNumber, toBlock, { filterKey });
98+
let logs = await this.getPastLogsRanges(ranges, events, toBlock, filter?.fromBlock, {
99+
params: filter?.params as any
100+
});
98101
return {
99102
logs: logs as any
100103
};
101104
}
102105

103106
async * getPastLogsStream <
104-
TLogName extends GetEventLogNames<T>,
107+
TLogName extends GetEventLogNames<TContract>,
105108
> (
106109
event: TLogName | TLogName[] | '*',
107110
// Fetch all logs and filter later if needed
@@ -110,10 +113,13 @@ export class EventsIndexer <T extends ContractBase> {
110113
fromBlock?: number
111114
toBlock?: number
112115
blockRangeLimits?: WClient['blockRangeLimits']
116+
params?: TLogName extends keyof TContract
117+
? (TContract[TLogName] extends (options: { params?: infer TParams }) => any ? TParams : never)
118+
: never,
113119
},
114120
): AsyncGenerator<
115121
TLogsRangeProgress<
116-
ITxLogItem<GetTypes<T>['Events'][TLogName]['outputParams'], string>
122+
ITxLogItem<GetTypes<TContract>['Events'][TLogName]['outputParams'], string>
117123
> // next result
118124
, void // void returns
119125
, void // next doesn't get any parameter
@@ -122,12 +128,16 @@ export class EventsIndexer <T extends ContractBase> {
122128
let client = contract.client;
123129
let toBlock = options?.toBlock ?? await client.getBlockNumber();
124130
let events = Array.isArray(event) ? event as string[] : [ event as string ];
125-
let ranges = await this.getRanges(events, options?.fromBlock ?? this.options.initialBlockNumber, toBlock);
131+
let filterKey = this.getFilterKey(options?.params);
132+
let ranges = await this.getRanges(events, options?.fromBlock ?? this.options.initialBlockNumber, toBlock, {
133+
filterKey
134+
});
126135

127136
let dfrInner = new class_Dfr<any>();
128137
let dfrOuter = new class_Dfr<any>();
129138

130139
this.getPastLogsRanges(ranges, events, toBlock, options?.fromBlock, {
140+
params: options?.params,
131141
blockRangeLimits: options?.blockRangeLimits,
132142
streamed: true,
133143
async onProgress (info) {
@@ -175,9 +185,14 @@ export class EventsIndexer <T extends ContractBase> {
175185
}
176186
}
177187

178-
private async getRanges (events: string[], initialBlockNumber: number, toBlock: number, fromBlock?: number): Promise<TRange[]> {
188+
private async getRanges (events: string[], initialBlockNumber: number, toBlock: number, opts: {
189+
fromBlock?: number
190+
filterKey?: string
191+
}): Promise<TRange[]> {
179192
let logsMetaArr = await this.storeMeta.fetch();
180-
let eventsBlock = alot(logsMetaArr).toDictionary(x => x.event, x => x.lastBlock);
193+
let eventsBlock = alot(logsMetaArr)
194+
.filter(x => x.filterKey == opts?.filterKey)
195+
.toDictionary(x => x.event, x => x.lastBlock);
181196
let logsMeta = events.map(event => {
182197
let blockNr = eventsBlock[event] ?? initialBlockNumber;
183198
return {
@@ -187,7 +202,7 @@ export class EventsIndexer <T extends ContractBase> {
187202
});
188203
let hasInitialBlock = logsMeta.every(x => x.lastBlock != null);
189204
if (hasInitialBlock === false) {
190-
let blockNr = fromBlock ?? await this.getInitialBlockNumber();
205+
let blockNr = opts?.fromBlock ?? await this.getInitialBlockNumber();
191206
logsMeta.filter(x => x.lastBlock == null).forEach(x => x.lastBlock = blockNr);
192207
};
193208

@@ -210,7 +225,7 @@ export class EventsIndexer <T extends ContractBase> {
210225
}
211226
return ranges;
212227
}
213-
private async getPastLogsRanges (ranges: TRange[], events: string[], toBlock: number, fromBlock?: number, options?: TEventLogOptions<TEth.Log>) {
228+
private async getPastLogsRanges (ranges: TRange[], events: string[], toBlock: number, fromBlock?: number, options?: TEventLogOptions<any>) {
214229
// Save indexed logs every 2 minutes
215230
const PERSIST_INTERVAL = $date.parseTimespan('2min');
216231
// Save indexed logs every 10k logs
@@ -225,7 +240,8 @@ export class EventsIndexer <T extends ContractBase> {
225240
let arr = await this.getItemsFromStore({
226241
fromBlock: fromBlock,
227242
toBlock: toBlock,
228-
events
243+
events,
244+
params: options?.params,
229245
});
230246
if (arr?.length > 0) {
231247
let latestBlock = arr[arr.length - 1].blockNumber;
@@ -266,6 +282,7 @@ export class EventsIndexer <T extends ContractBase> {
266282
fromBlock: fromBlock,
267283
toBlock: toBlock,
268284
blockRangeLimits: options?.blockRangeLimits,
285+
params: options?.params,
269286
onProgress: async info => {
270287
onProgressCount++;
271288

@@ -302,7 +319,7 @@ export class EventsIndexer <T extends ContractBase> {
302319
buffer = [];
303320
time = now;
304321
savedCount += arr.length;
305-
await this.upsert(arr, events, info.latestBlock);
322+
await this.upsert(arr, events, info.latestBlock, options);
306323
}
307324

308325
if (options?.onProgress) {
@@ -314,13 +331,13 @@ export class EventsIndexer <T extends ContractBase> {
314331
});
315332

316333
if (buffer.length > 0) {
317-
await this.upsert(buffer, events, toBlock);
334+
await this.upsert(buffer, events, toBlock, options);
318335
}
319336
}
320337

321338

322339
// Upsert final, if buffer is empty, we still persist the toBlock
323-
await this.upsert(buffer, events, toBlock);
340+
await this.upsert(buffer, events, toBlock, options);
324341

325342
if (isStreamed === true) {
326343
return;
@@ -329,7 +346,8 @@ export class EventsIndexer <T extends ContractBase> {
329346
let logs = await this.getItemsFromStore({
330347
fromBlock: fromBlock,
331348
toBlock: toBlock + 1,
332-
events: events
349+
events: events,
350+
params: options?.params
333351
});
334352

335353
return logs;
@@ -340,16 +358,27 @@ export class EventsIndexer <T extends ContractBase> {
340358
fromBlock?: number
341359
toBlock?: number
342360
events?: string[]
361+
params?: Record<string, any>
343362
}) {
344363
let arr = await this.store.fetch(filter);
345364
let events = filter.events;
346365
if (events?.[0] !== '*') {
347366
let requestedEvents = alot(events).toDictionary(x => x);
348367
arr = arr.filter(x => x.event in requestedEvents);
349368
}
350-
369+
let filterKey = this.getFilterKey(filter.params);
370+
arr = arr.filter(x => x.filterKey == filterKey);
351371
return arr;
352372
}
373+
private getFilterKey (params) {
374+
if (params == null) {
375+
return;
376+
}
377+
let arr = Array.isArray(params)
378+
? params
379+
: Object.keys(params).map(key => `${key}=${params[key]}`);
380+
return arr.join('_');
381+
}
353382

354383
private async getInitialBlockNumber () {
355384
let client = this.contract.client;
@@ -363,11 +392,19 @@ export class EventsIndexer <T extends ContractBase> {
363392
}
364393

365394
@memd.deco.queued()
366-
private async upsert (logs, events: string[], latestBlock: number) {
395+
private async upsert (logs: TEventsIndexerItem[], events: string[], latestBlock: number, options: { params? }) {
396+
let filterKey = this.getFilterKey(options?.params);
367397
if (logs?.length > 0) {
398+
for (let log of logs) {
399+
log.filterKey = filterKey;
400+
}
368401
await this.store.upsertMany(logs);
369402
}
370-
const logsMeta = events.map(event => ({ event, lastBlock: latestBlock }));
403+
const logsMeta = events.map(event => ({
404+
event,
405+
lastBlock: latestBlock,
406+
filterKey: filterKey,
407+
}));
371408
await this.storeMeta.upsertMany(logsMeta);
372409
}
373410
}

src/indexer/storage/FsEventsMetaStore.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export class FsEventsMetaStore <T extends ContractBase> implements IEventsIndexe
3333

3434
this.store = new JsonArrayStore<TEventsIndexerMeta>({
3535
path: `${directory}meta-arr.json`,
36-
key: x => x.event
36+
key: x => (x.event + (x.filterKey || ''))
3737
});
3838

3939
this.storeV0 = new JsonArrayStore<TEventsIndexerMeta>({

src/indexer/storage/interfaces.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
11
import { ITxLogItem } from '@dequanto/txs/receipt/ITxLogItem'
22

3-
type TItem = ITxLogItem<any>
3+
export type TEventsIndexerItem = ITxLogItem<any> & {
4+
filterKey?: string
5+
}
46

57
export type TEventsIndexerMeta = {
68
event: string
79
lastBlock: number
10+
filterKey?: string
811
}
912

1013
export interface IEventsIndexerStore {
11-
upsertMany(logs: TItem[]): Promise<TItem[]>
12-
removeMany(logs: TItem[]): Promise<any>
14+
upsertMany(logs: TEventsIndexerItem[]): Promise<TEventsIndexerItem[]>
15+
removeMany(logs: TEventsIndexerItem[]): Promise<any>
1316

1417
fetch (options?: {
1518
fromBlock?: number
1619
toBlock?: number
17-
}): Promise<TItem[]>
20+
}): Promise<TEventsIndexerItem[]>
1821

1922
merge (store: IEventsIndexerStore): Promise<any>
2023
}

test/indexer/EventsIndexer.spec.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { HardhatProvider } from '@dequanto/hardhat/HardhatProvider';
22
import { EventsIndexer } from '@dequanto/indexer/EventsIndexer';
33
import { $date } from '@dequanto/utils/$date';
4+
import alot from 'alot';
45
import { File, Directory } from 'atma-io';
56

67
const FS_DIR = './test/tmp/data/logs/';
@@ -18,7 +19,7 @@ UTest({
1819
let client = hh.client();
1920
let code = `
2021
contract Foo {
21-
event Number (uint256 num);
22+
event Number (uint256 indexed num);
2223
event String (string str);
2324
2425
function emitNumber(uint num) external {
@@ -110,10 +111,16 @@ UTest({
110111

111112
let storageData3rdWeek = await File.readAsync<any[]>(`${BASE_DIR}${WEEK_SECONDS * 3}-${WEEK_SECONDS * 4}.json`);
112113
eq_(storageData3rdWeek.length, 1);
114+
115+
let events = await indexer.getPastLogs('Number', { params: {
116+
num: '0x2'
117+
} });
118+
119+
let nums = alot(events.logs).map(x => x.params.num).toArray();
120+
deepEq_(nums, [2n]);
113121
},
114122
async 'fetch events streamed' () {
115123

116-
117124
let hh = new HardhatProvider();
118125
let deployer = hh.deployer();
119126
let client = hh.client();

0 commit comments

Comments
 (0)